vagrant-aws-iam-decoder 0.7.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +21 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +19 -0
  5. data/CHANGELOG.md +96 -0
  6. data/Gemfile +12 -0
  7. data/LICENSE +8 -0
  8. data/README.md +326 -0
  9. data/Rakefile +22 -0
  10. data/dummy.box +0 -0
  11. data/example_box/README.md +13 -0
  12. data/example_box/metadata.json +3 -0
  13. data/lib/vagrant-aws-iam-decoder.rb +18 -0
  14. data/lib/vagrant-aws/action.rb +210 -0
  15. data/lib/vagrant-aws/action/connect_aws.rb +48 -0
  16. data/lib/vagrant-aws/action/elb_deregister_instance.rb +24 -0
  17. data/lib/vagrant-aws/action/elb_register_instance.rb +24 -0
  18. data/lib/vagrant-aws/action/is_created.rb +18 -0
  19. data/lib/vagrant-aws/action/is_stopped.rb +18 -0
  20. data/lib/vagrant-aws/action/message_already_created.rb +16 -0
  21. data/lib/vagrant-aws/action/message_not_created.rb +16 -0
  22. data/lib/vagrant-aws/action/message_will_not_destroy.rb +16 -0
  23. data/lib/vagrant-aws/action/package_instance.rb +192 -0
  24. data/lib/vagrant-aws/action/read_ssh_info.rb +53 -0
  25. data/lib/vagrant-aws/action/read_state.rb +38 -0
  26. data/lib/vagrant-aws/action/run_instance.rb +396 -0
  27. data/lib/vagrant-aws/action/start_instance.rb +81 -0
  28. data/lib/vagrant-aws/action/stop_instance.rb +28 -0
  29. data/lib/vagrant-aws/action/terminate_instance.rb +51 -0
  30. data/lib/vagrant-aws/action/timed_provision.rb +21 -0
  31. data/lib/vagrant-aws/action/wait_for_state.rb +41 -0
  32. data/lib/vagrant-aws/action/warn_networks.rb +19 -0
  33. data/lib/vagrant-aws/config.rb +601 -0
  34. data/lib/vagrant-aws/errors.rb +43 -0
  35. data/lib/vagrant-aws/plugin.rb +73 -0
  36. data/lib/vagrant-aws/provider.rb +50 -0
  37. data/lib/vagrant-aws/util/elb.rb +58 -0
  38. data/lib/vagrant-aws/util/timer.rb +17 -0
  39. data/lib/vagrant-aws/version.rb +5 -0
  40. data/locales/en.yml +161 -0
  41. data/spec/spec_helper.rb +1 -0
  42. data/spec/vagrant-aws/config_spec.rb +395 -0
  43. data/templates/metadata.json.erb +3 -0
  44. data/templates/vagrant-aws_package_Vagrantfile.erb +5 -0
  45. data/vagrant-aws-iam-decoder.gemspec +62 -0
  46. metadata +163 -0
@@ -0,0 +1,81 @@
1
+ require "log4r"
2
+
3
+ require 'vagrant/util/retryable'
4
+
5
+ require 'vagrant-aws/util/timer'
6
+
7
+ module VagrantPlugins
8
+ module AWS
9
+ module Action
10
+ # This starts a stopped instance.
11
+ class StartInstance
12
+ include Vagrant::Util::Retryable
13
+
14
+ def initialize(app, env)
15
+ @app = app
16
+ @logger = Log4r::Logger.new("vagrant_aws::action::start_instance")
17
+ end
18
+
19
+ def call(env)
20
+ # Initialize metrics if they haven't been
21
+ env[:metrics] ||= {}
22
+
23
+ server = env[:aws_compute].servers.get(env[:machine].id)
24
+
25
+ env[:ui].info(I18n.t("vagrant_aws.starting"))
26
+
27
+ begin
28
+ server.start
29
+
30
+ region = env[:machine].provider_config.region
31
+ region_config = env[:machine].provider_config.get_region_config(region)
32
+
33
+ # Wait for the instance to be ready first
34
+ env[:metrics]["instance_ready_time"] = Util::Timer.time do
35
+ tries = region_config.instance_ready_timeout / 2
36
+
37
+ env[:ui].info(I18n.t("vagrant_aws.waiting_for_ready"))
38
+ begin
39
+ retryable(:on => Fog::Errors::TimeoutError, :tries => tries) do
40
+ # If we're interrupted don't worry about waiting
41
+ next if env[:interrupted]
42
+
43
+ # Wait for the server to be ready
44
+ server.wait_for(2) { ready? }
45
+ end
46
+ rescue Fog::Errors::TimeoutError
47
+ # Notify the user
48
+ raise Errors::InstanceReadyTimeout,
49
+ timeout: region_config.instance_ready_timeout
50
+ end
51
+ end
52
+ rescue Fog::Compute::AWS::Error => e
53
+ raise Errors::FogError, :message => e.message
54
+ end
55
+
56
+ @logger.info("Time to instance ready: #{env[:metrics]["instance_ready_time"]}")
57
+
58
+ if !env[:interrupted]
59
+ env[:metrics]["instance_ssh_time"] = Util::Timer.time do
60
+ # Wait for SSH to be ready.
61
+ env[:ui].info(I18n.t("vagrant_aws.waiting_for_ssh"))
62
+ while true
63
+ # If we're interrupted then just back out
64
+ break if env[:interrupted]
65
+ break if env[:machine].communicate.ready?
66
+ sleep 2
67
+ end
68
+ end
69
+
70
+ @logger.info("Time for SSH ready: #{env[:metrics]["instance_ssh_time"]}")
71
+
72
+ # Ready and booted!
73
+ env[:ui].info(I18n.t("vagrant_aws.ready"))
74
+ end
75
+
76
+ @app.call(env)
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,28 @@
1
+ require "log4r"
2
+
3
+ module VagrantPlugins
4
+ module AWS
5
+ module Action
6
+ # This stops the running instance.
7
+ class StopInstance
8
+ def initialize(app, env)
9
+ @app = app
10
+ @logger = Log4r::Logger.new("vagrant_aws::action::stop_instance")
11
+ end
12
+
13
+ def call(env)
14
+ server = env[:aws_compute].servers.get(env[:machine].id)
15
+
16
+ if env[:machine].state.id == :stopped
17
+ env[:ui].info(I18n.t("vagrant_aws.already_status", :status => env[:machine].state.id))
18
+ else
19
+ env[:ui].info(I18n.t("vagrant_aws.stopping"))
20
+ server.stop(!!env[:force_halt])
21
+ end
22
+
23
+ @app.call(env)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,51 @@
1
+ require "log4r"
2
+ require "json"
3
+
4
+ module VagrantPlugins
5
+ module AWS
6
+ module Action
7
+ # This terminates the running instance.
8
+ class TerminateInstance
9
+ def initialize(app, env)
10
+ @app = app
11
+ @logger = Log4r::Logger.new("vagrant_aws::action::terminate_instance")
12
+ end
13
+
14
+ def call(env)
15
+ server = env[:aws_compute].servers.get(env[:machine].id)
16
+ region = env[:machine].provider_config.region
17
+ region_config = env[:machine].provider_config.get_region_config(region)
18
+
19
+ elastic_ip = region_config.elastic_ip
20
+
21
+ # Release the elastic IP
22
+ ip_file = env[:machine].data_dir.join('elastic_ip')
23
+ if ip_file.file?
24
+ release_address(env,ip_file.read)
25
+ ip_file.delete
26
+ end
27
+
28
+ # Destroy the server and remove the tracking ID
29
+ env[:ui].info(I18n.t("vagrant_aws.terminating"))
30
+ server.destroy
31
+ env[:machine].id = nil
32
+
33
+ @app.call(env)
34
+ end
35
+
36
+ # Release an elastic IP address
37
+ def release_address(env,eip)
38
+ h = JSON.parse(eip)
39
+ # Use association_id and allocation_id for VPC, use public IP for EC2
40
+ if h['association_id']
41
+ env[:aws_compute].disassociate_address(nil,h['association_id'])
42
+ env[:aws_compute].release_address(h['allocation_id'])
43
+ else
44
+ env[:aws_compute].disassociate_address(h['public_ip'])
45
+ env[:aws_compute].release_address(h['public_ip'])
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,21 @@
1
+ require "vagrant-aws/util/timer"
2
+
3
+ module VagrantPlugins
4
+ module AWS
5
+ module Action
6
+ # This is the same as the builtin provision except it times the
7
+ # provisioner runs.
8
+ class TimedProvision < Vagrant::Action::Builtin::Provision
9
+ def run_provisioner(env, name, p)
10
+ timer = Util::Timer.time do
11
+ super
12
+ end
13
+
14
+ env[:metrics] ||= {}
15
+ env[:metrics]["provisioner_times"] ||= []
16
+ env[:metrics]["provisioner_times"] << [name, timer]
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,41 @@
1
+ require "log4r"
2
+ require "timeout"
3
+
4
+ module VagrantPlugins
5
+ module AWS
6
+ module Action
7
+ # This action will wait for a machine to reach a specific state or quit by timeout
8
+ class WaitForState
9
+ # env[:result] will be false in case of timeout.
10
+ # @param [Symbol] state Target machine state.
11
+ # @param [Number] timeout Timeout in seconds.
12
+ def initialize(app, env, state, timeout)
13
+ @app = app
14
+ @logger = Log4r::Logger.new("vagrant_aws::action::wait_for_state")
15
+ @state = state
16
+ @timeout = timeout
17
+ end
18
+
19
+ def call(env)
20
+ env[:result] = true
21
+ if env[:machine].state.id == @state
22
+ @logger.info(I18n.t("vagrant_aws.already_status", :status => @state))
23
+ else
24
+ @logger.info("Waiting for machine to reach state #{@state}")
25
+ begin
26
+ Timeout.timeout(@timeout) do
27
+ until env[:machine].state.id == @state
28
+ sleep 2
29
+ end
30
+ end
31
+ rescue Timeout::Error
32
+ env[:result] = false # couldn't reach state in time
33
+ end
34
+ end
35
+
36
+ @app.call(env)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,19 @@
1
+ module VagrantPlugins
2
+ module AWS
3
+ module Action
4
+ class WarnNetworks
5
+ def initialize(app, env)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ if env[:machine].config.vm.networks.length > 0
11
+ env[:ui].warn(I18n.t("vagrant_aws.warn_networks"))
12
+ end
13
+
14
+ @app.call(env)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,601 @@
1
+ require "vagrant"
2
+ require "iniparse"
3
+
4
+ module VagrantPlugins
5
+ module AWS
6
+ class Config < Vagrant.plugin("2", :config)
7
+ # The access key ID for accessing AWS.
8
+ #
9
+ # @return [String]
10
+ attr_accessor :access_key_id
11
+
12
+ # The ID of the AMI to use.
13
+ #
14
+ # @return [String]
15
+ attr_accessor :ami
16
+
17
+ # The availability zone to launch the instance into. If nil, it will
18
+ # use the default for your account.
19
+ #
20
+ # @return [String]
21
+ attr_accessor :availability_zone
22
+
23
+ # The timeout to wait for an instance to become ready.
24
+ #
25
+ # @return [Fixnum]
26
+ attr_accessor :instance_ready_timeout
27
+
28
+ # The interval to wait for checking an instance's state.
29
+ #
30
+ # @return [Fixnum]
31
+ attr_accessor :instance_check_interval
32
+
33
+ # The timeout to wait for an instance to successfully burn into an AMI.
34
+ #
35
+ # @return [Fixnum]
36
+ attr_accessor :instance_package_timeout
37
+
38
+ # The type of instance to launch, such as "m3.medium"
39
+ #
40
+ # @return [String]
41
+ attr_accessor :instance_type
42
+
43
+ # The name of the keypair to use.
44
+ #
45
+ # @return [String]
46
+ attr_accessor :keypair_name
47
+
48
+ # The private IP address to give this machine (VPC).
49
+ #
50
+ # @return [String]
51
+ attr_accessor :private_ip_address
52
+
53
+ # If true, acquire and attach an elastic IP address.
54
+ # If set to an IP address, assign to the instance.
55
+ #
56
+ # @return [String]
57
+ attr_accessor :elastic_ip
58
+
59
+ # The name of the AWS region in which to create the instance.
60
+ #
61
+ # @return [String]
62
+ attr_accessor :region
63
+
64
+ # The EC2 endpoint to connect to
65
+ #
66
+ # @return [String]
67
+ attr_accessor :endpoint
68
+
69
+ # The version of the AWS api to use
70
+ #
71
+ # @return [String]
72
+ attr_accessor :version
73
+
74
+ # The secret access key for accessing AWS.
75
+ #
76
+ # @return [String]
77
+ attr_accessor :secret_access_key
78
+
79
+ # The token associated with the key for accessing AWS.
80
+ #
81
+ # @return [String]
82
+ attr_accessor :session_token
83
+
84
+ # The security groups to set on the instance. For VPC this must
85
+ # be a list of IDs. For EC2, it can be either.
86
+ #
87
+ # @return [Array<String>]
88
+ attr_reader :security_groups
89
+
90
+ # The Amazon resource name (ARN) of the IAM Instance Profile
91
+ # to associate with the instance.
92
+ #
93
+ # @return [String]
94
+ attr_accessor :iam_instance_profile_arn
95
+
96
+ # The name of the IAM Instance Profile to associate with
97
+ # the instance.
98
+ #
99
+ # @return [String]
100
+ attr_accessor :iam_instance_profile_name
101
+
102
+ # The subnet ID to launch the machine into (VPC).
103
+ #
104
+ # @return [String]
105
+ attr_accessor :subnet_id
106
+
107
+ # The tags for the machine.
108
+ #
109
+ # @return [Hash<String, String>]
110
+ attr_accessor :tags
111
+
112
+ # The tags for the AMI generated with package.
113
+ #
114
+ # @return [Hash<String, String>]
115
+ attr_accessor :package_tags
116
+
117
+ # Use IAM Instance Role for authentication to AWS instead of an
118
+ # explicit access_id and secret_access_key
119
+ #
120
+ # @return [Boolean]
121
+ attr_accessor :use_iam_profile
122
+
123
+ # The user data string
124
+ #
125
+ # @return [String]
126
+ attr_accessor :user_data
127
+
128
+ # Block device mappings
129
+ #
130
+ # @return [Array<Hash>]
131
+ attr_accessor :block_device_mapping
132
+
133
+ # Indicates whether an instance stops or terminates when you initiate shutdown from the instance
134
+ #
135
+ # @return [bool]
136
+ attr_accessor :terminate_on_shutdown
137
+
138
+ # Specifies which address to connect to with ssh
139
+ # Must be one of:
140
+ # - :public_ip_address
141
+ # - :dns_name
142
+ # - :private_ip_address
143
+ # This attribute also accepts an array of symbols
144
+ #
145
+ # @return [Symbol]
146
+ attr_accessor :ssh_host_attribute
147
+
148
+ # Enables Monitoring
149
+ #
150
+ # @return [Boolean]
151
+ attr_accessor :monitoring
152
+
153
+ # EBS optimized instance
154
+ #
155
+ # @return [Boolean]
156
+ attr_accessor :ebs_optimized
157
+
158
+ # Source Destination check
159
+ #
160
+ # @return [Boolean]
161
+ attr_accessor :source_dest_check
162
+
163
+ # Assigning a public IP address in a VPC
164
+ #
165
+ # @return [Boolean]
166
+ attr_accessor :associate_public_ip
167
+
168
+ # The name of ELB, which an instance should be
169
+ # attached to
170
+ #
171
+ # @return [String]
172
+ attr_accessor :elb
173
+
174
+ # Disable unregisering ELB's from AZ - useful in case of not using default VPC
175
+ # @return [Boolean]
176
+ attr_accessor :unregister_elb_from_az
177
+
178
+ # Kernel Id
179
+ #
180
+ # @return [String]
181
+ attr_accessor :kernel_id
182
+
183
+ # The tenancy of the instance in a VPC.
184
+ # Defaults to 'default'.
185
+ #
186
+ # @return [String]
187
+ attr_accessor :tenancy
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
+
199
+ # Launch as spot instance
200
+ #
201
+ # @return [Boolean]
202
+ attr_accessor :spot_instance
203
+
204
+ # Spot request max price
205
+ #
206
+ # @return [String]
207
+ attr_accessor :spot_max_price
208
+
209
+ # Spot request validity
210
+ #
211
+ # @return [Time]
212
+ attr_accessor :spot_valid_until
213
+
214
+ # The product description for the spot price history
215
+ #
216
+ # @return [String]
217
+ attr_accessor :spot_price_product_description
218
+
219
+ def initialize(region_specific=false)
220
+ @access_key_id = UNSET_VALUE
221
+ @ami = UNSET_VALUE
222
+ @availability_zone = UNSET_VALUE
223
+ @instance_check_interval = UNSET_VALUE
224
+ @instance_ready_timeout = UNSET_VALUE
225
+ @instance_package_timeout = UNSET_VALUE
226
+ @instance_type = UNSET_VALUE
227
+ @keypair_name = UNSET_VALUE
228
+ @private_ip_address = UNSET_VALUE
229
+ @region = UNSET_VALUE
230
+ @endpoint = UNSET_VALUE
231
+ @version = UNSET_VALUE
232
+ @secret_access_key = UNSET_VALUE
233
+ @session_token = UNSET_VALUE
234
+ @security_groups = UNSET_VALUE
235
+ @subnet_id = UNSET_VALUE
236
+ @tags = {}
237
+ @package_tags = {}
238
+ @user_data = UNSET_VALUE
239
+ @use_iam_profile = UNSET_VALUE
240
+ @block_device_mapping = []
241
+ @elastic_ip = UNSET_VALUE
242
+ @iam_instance_profile_arn = UNSET_VALUE
243
+ @iam_instance_profile_name = UNSET_VALUE
244
+ @terminate_on_shutdown = UNSET_VALUE
245
+ @ssh_host_attribute = UNSET_VALUE
246
+ @monitoring = UNSET_VALUE
247
+ @ebs_optimized = UNSET_VALUE
248
+ @source_dest_check = UNSET_VALUE
249
+ @associate_public_ip = UNSET_VALUE
250
+ @elb = UNSET_VALUE
251
+ @unregister_elb_from_az = UNSET_VALUE
252
+ @kernel_id = UNSET_VALUE
253
+ @tenancy = UNSET_VALUE
254
+ @aws_dir = UNSET_VALUE
255
+ @aws_profile = UNSET_VALUE
256
+ @spot_instance = UNSET_VALUE
257
+ @spot_max_price = UNSET_VALUE
258
+ @spot_valid_until = UNSET_VALUE
259
+
260
+ # Internal state (prefix with __ so they aren't automatically
261
+ # merged)
262
+ @__compiled_region_configs = {}
263
+ @__finalized = false
264
+ @__region_config = {}
265
+ @__region_specific = region_specific
266
+ end
267
+
268
+ # set security_groups
269
+ def security_groups=(value)
270
+ # convert value to array if necessary
271
+ @security_groups = value.is_a?(Array) ? value : [value]
272
+ end
273
+
274
+ # Allows region-specific overrides of any of the settings on this
275
+ # configuration object. This allows the user to override things like
276
+ # AMI and keypair name for regions. Example:
277
+ #
278
+ # aws.region_config "us-east-1" do |region|
279
+ # region.ami = "ami-12345678"
280
+ # region.keypair_name = "company-east"
281
+ # end
282
+ #
283
+ # @param [String] region The region name to configure.
284
+ # @param [Hash] attributes Direct attributes to set on the configuration
285
+ # as a shortcut instead of specifying a full block.
286
+ # @yield [config] Yields a new AWS configuration.
287
+ def region_config(region, attributes=nil, &block)
288
+ # Append the block to the list of region configs for that region.
289
+ # We'll evaluate these upon finalization.
290
+ @__region_config[region] ||= []
291
+
292
+ # Append a block that sets attributes if we got one
293
+ if attributes
294
+ attr_block = lambda do |config|
295
+ config.set_options(attributes)
296
+ end
297
+
298
+ @__region_config[region] << attr_block
299
+ end
300
+
301
+ # Append a block if we got one
302
+ @__region_config[region] << block if block_given?
303
+ end
304
+
305
+ #-------------------------------------------------------------------
306
+ # Internal methods.
307
+ #-------------------------------------------------------------------
308
+
309
+ def merge(other)
310
+ super.tap do |result|
311
+ # Copy over the region specific flag. "True" is retained if either
312
+ # has it.
313
+ new_region_specific = other.instance_variable_get(:@__region_specific)
314
+ result.instance_variable_set(
315
+ :@__region_specific, new_region_specific || @__region_specific)
316
+
317
+ # Go through all the region configs and prepend ours onto
318
+ # theirs.
319
+ new_region_config = other.instance_variable_get(:@__region_config)
320
+ @__region_config.each do |key, value|
321
+ new_region_config[key] ||= []
322
+ new_region_config[key] = value + new_region_config[key]
323
+ end
324
+
325
+ # Set it
326
+ result.instance_variable_set(:@__region_config, new_region_config)
327
+
328
+ # Merge in the tags
329
+ result.tags.merge!(self.tags)
330
+ result.tags.merge!(other.tags)
331
+
332
+ # Merge in the package tags
333
+ result.package_tags.merge!(self.package_tags)
334
+ result.package_tags.merge!(other.package_tags)
335
+
336
+ # Merge block_device_mapping
337
+ result.block_device_mapping |= self.block_device_mapping
338
+ result.block_device_mapping |= other.block_device_mapping
339
+ end
340
+ end
341
+
342
+ def finalize!
343
+ # If access_key_id or secret_access_key were not specified in Vagrantfile
344
+ # then try to read from environment variables first, and if it fails from
345
+ # the AWS folder.
346
+ if @access_key_id == UNSET_VALUE or @secret_access_key == UNSET_VALUE
347
+ @aws_profile = 'default' if @aws_profile == UNSET_VALUE
348
+ @aws_dir = ENV['HOME'].to_s + '/.aws/' if @aws_dir == UNSET_VALUE
349
+ @aws_region, @access_key_id, @secret_access_key, @session_token = Credentials.new.get_aws_info(@aws_profile, @aws_dir)
350
+ @region = @aws_region if @region == UNSET_VALUE and !@aws_region.nil?
351
+ else
352
+ @aws_profile = nil
353
+ @aws_dir = nil
354
+ end
355
+
356
+ # session token must be set to nil, empty string isn't enough!
357
+ @session_token = nil if @session_token == UNSET_VALUE
358
+
359
+ # AMI must be nil, since we can't default that
360
+ @ami = nil if @ami == UNSET_VALUE
361
+
362
+ # Set the default timeout for waiting for an instance to be ready
363
+ @instance_ready_timeout = 120 if @instance_ready_timeout == UNSET_VALUE
364
+
365
+ # Set the default interval to check instance state
366
+ @instance_check_interval = 2 if @instance_check_interval == UNSET_VALUE
367
+
368
+ # Set the default timeout for waiting for an instance to burn into and ami
369
+ @instance_package_timeout = 600 if @instance_package_timeout == UNSET_VALUE
370
+
371
+ # Default instance type is an m3.medium
372
+ @instance_type = "m3.medium" if @instance_type == UNSET_VALUE
373
+
374
+ # Keypair defaults to nil
375
+ @keypair_name = nil if @keypair_name == UNSET_VALUE
376
+
377
+ # Default the private IP to nil since VPC is not default
378
+ @private_ip_address = nil if @private_ip_address == UNSET_VALUE
379
+
380
+ # Acquire an elastic IP if requested
381
+ @elastic_ip = nil if @elastic_ip == UNSET_VALUE
382
+
383
+ # Default region is us-east-1. This is sensible because AWS
384
+ # generally defaults to this as well.
385
+ @region = "us-east-1" if @region == UNSET_VALUE
386
+ @availability_zone = nil if @availability_zone == UNSET_VALUE
387
+ @endpoint = nil if @endpoint == UNSET_VALUE
388
+ @version = nil if @version == UNSET_VALUE
389
+
390
+ # The security groups are empty by default.
391
+ @security_groups = [] if @security_groups == UNSET_VALUE
392
+
393
+ # Subnet is nil by default otherwise we'd launch into VPC.
394
+ @subnet_id = nil if @subnet_id == UNSET_VALUE
395
+
396
+ # IAM Instance profile arn/name is nil by default.
397
+ @iam_instance_profile_arn = nil if @iam_instance_profile_arn == UNSET_VALUE
398
+ @iam_instance_profile_name = nil if @iam_instance_profile_name == UNSET_VALUE
399
+
400
+ # By default we don't use an IAM profile
401
+ @use_iam_profile = false if @use_iam_profile == UNSET_VALUE
402
+
403
+ # User Data is nil by default
404
+ @user_data = nil if @user_data == UNSET_VALUE
405
+
406
+ # default false
407
+ @terminate_on_shutdown = false if @terminate_on_shutdown == UNSET_VALUE
408
+
409
+ # default to nil
410
+ @ssh_host_attribute = nil if @ssh_host_attribute == UNSET_VALUE
411
+
412
+ # default false
413
+ @monitoring = false if @monitoring == UNSET_VALUE
414
+
415
+ # default false
416
+ @ebs_optimized = false if @ebs_optimized == UNSET_VALUE
417
+
418
+ # default to nil
419
+ @source_dest_check = nil if @source_dest_check == UNSET_VALUE
420
+
421
+ # default false
422
+ @associate_public_ip = false if @associate_public_ip == UNSET_VALUE
423
+
424
+ # default 'default'
425
+ @tenancy = "default" if @tenancy == UNSET_VALUE
426
+
427
+ # Don't attach instance to any ELB by default
428
+ @elb = nil if @elb == UNSET_VALUE
429
+
430
+ @unregister_elb_from_az = true if @unregister_elb_from_az == UNSET_VALUE
431
+
432
+ # default to nil
433
+ @kernel_id = nil if @kernel_id == UNSET_VALUE
434
+
435
+ # By default don't use spot requests
436
+ @spot_instance = false if @spot_instance == UNSET_VALUE
437
+
438
+ # default to nil
439
+ @spot_max_price = nil if @spot_max_price == UNSET_VALUE
440
+
441
+ # Default: Request is effective indefinitely.
442
+ @spot_valid_until = nil if @spot_valid_until == UNSET_VALUE
443
+
444
+ # default to nil
445
+ @spot_price_product_description = nil if @spot_price_product_description == UNSET_VALUE
446
+
447
+ # Compile our region specific configurations only within
448
+ # NON-REGION-SPECIFIC configurations.
449
+ if !@__region_specific
450
+ @__region_config.each do |region, blocks|
451
+ config = self.class.new(true).merge(self)
452
+
453
+ # Execute the configuration for each block
454
+ blocks.each { |b| b.call(config) }
455
+
456
+ # The region name of the configuration always equals the
457
+ # region config name:
458
+ config.region = region
459
+
460
+ # Finalize the configuration
461
+ config.finalize!
462
+
463
+ # Store it for retrieval
464
+ @__compiled_region_configs[region] = config
465
+ end
466
+ end
467
+
468
+ # Mark that we finalized
469
+ @__finalized = true
470
+ end
471
+
472
+ def validate(machine)
473
+ errors = _detected_errors
474
+
475
+ errors << I18n.t("vagrant_aws.config.aws_info_required",
476
+ :profile => @aws_profile, :location => @aws_dir) if \
477
+ @aws_profile and (@access_key_id.nil? or @secret_access_key.nil? or @region.nil?)
478
+
479
+ errors << I18n.t("vagrant_aws.config.region_required") if @region.nil?
480
+
481
+ if @region
482
+ # Get the configuration for the region we're using and validate only
483
+ # that region.
484
+ config = get_region_config(@region)
485
+
486
+ if !config.use_iam_profile
487
+ errors << I18n.t("vagrant_aws.config.access_key_id_required") if \
488
+ config.access_key_id.nil?
489
+ errors << I18n.t("vagrant_aws.config.secret_access_key_required") if \
490
+ config.secret_access_key.nil?
491
+ end
492
+
493
+ if config.associate_public_ip && !config.subnet_id
494
+ errors << I18n.t("vagrant_aws.config.subnet_id_required_with_public_ip")
495
+ end
496
+
497
+ errors << I18n.t("vagrant_aws.config.ami_required", :region => @region) if config.ami.nil?
498
+ end
499
+
500
+ { "AWS Provider" => errors }
501
+ end
502
+
503
+ # This gets the configuration for a specific region. It shouldn't
504
+ # be called by the general public and is only used internally.
505
+ def get_region_config(name)
506
+ if !@__finalized
507
+ raise "Configuration must be finalized before calling this method."
508
+ end
509
+
510
+ # Return the compiled region config
511
+ @__compiled_region_configs[name] || self
512
+ end
513
+ end
514
+
515
+
516
+ class Credentials < Vagrant.plugin("2", :config)
517
+ # This module reads AWS config and credentials.
518
+ # Behaviour aims to mimic what is described in AWS documentation:
519
+ # http://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html
520
+ # http://docs.aws.amazon.com/cli/latest/topic/config-vars.html
521
+ # Which is the following (stopping at the first successful case):
522
+ # 1) read config and credentials from environment variables
523
+ # 2) read config and credentials from files at location defined by environment variables
524
+ # 3) read config and credentials from files at default location
525
+ #
526
+ # The mandatory fields for a successful "get credentials" are the id and the secret keys.
527
+ # Region is not required since Config#finalize falls back to sensible defaults.
528
+ # The behaviour is all-or-nothing (ie: no mixing between vars and files).
529
+ #
530
+ # It also allows choosing a profile (by default it's [default]) and an "info"
531
+ # directory (by default $HOME/.aws), which can be specified in the Vagrantfile.
532
+ # Supported information: region, aws_access_key_id, aws_secret_access_key, and aws_session_token.
533
+
534
+ def get_aws_info(profile, location)
535
+ # read credentials from environment variables
536
+ aws_region, aws_id, aws_secret, aws_token = read_aws_environment()
537
+ # if nothing there, then read from files
538
+ # (the _if_ doesn't check aws_region since Config#finalize sets one by default)
539
+ if aws_id.to_s == '' or aws_secret.to_s == ''
540
+ # check if there are env variables for credential location, if so use then
541
+ aws_config = ENV['AWS_CONFIG_FILE'].to_s
542
+ aws_creds = ENV['AWS_SHARED_CREDENTIALS_FILE'].to_s
543
+ if aws_config == '' or aws_creds == ''
544
+ aws_config = location + 'config'
545
+ aws_creds = location + 'credentials'
546
+ end
547
+ if File.exist?(aws_config) and File.exist?(aws_creds)
548
+ aws_region, aws_id, aws_secret, aws_token = read_aws_files(profile, aws_config, aws_creds)
549
+ end
550
+ end
551
+ aws_region = nil if aws_region == ''
552
+ aws_id = nil if aws_id == ''
553
+ aws_secret = nil if aws_secret == ''
554
+ aws_token = nil if aws_token == ''
555
+
556
+ return aws_region, aws_id, aws_secret, aws_token
557
+ end
558
+
559
+
560
+ private
561
+
562
+ def read_aws_files(profile, aws_config, aws_creds)
563
+ # get info from config ini file for selected profile
564
+ data = File.read(aws_config)
565
+ doc_cfg = IniParse.parse(data)
566
+
567
+ # determine section in config ini file
568
+ if profile == 'default' || !doc_cfg[profile].nil?
569
+ ini_profile = profile
570
+ else
571
+ ini_profile = 'profile ' + profile
572
+ end
573
+
574
+ aws_region = doc_cfg[ini_profile]['region']
575
+
576
+ # determine section in credentials ini file
577
+ ini_profile = profile
578
+ # get info from credentials ini file for selected profile
579
+ data = File.read(aws_creds)
580
+ doc_cfg = IniParse.parse(data)
581
+ aws_id = doc_cfg[ini_profile]['aws_access_key_id']
582
+ aws_secret = doc_cfg[ini_profile]['aws_secret_access_key']
583
+ aws_token = doc_cfg[ini_profile]['aws_session_token']
584
+
585
+ return aws_region, aws_id, aws_secret, aws_token
586
+ end
587
+
588
+ def read_aws_environment()
589
+ aws_region = ENV['AWS_DEFAULT_REGION']
590
+ aws_id = ENV['AWS_ACCESS_KEY_ID']
591
+ aws_secret = ENV['AWS_SECRET_ACCESS_KEY']
592
+ aws_token = ENV['AWS_SESSION_TOKEN']
593
+
594
+ return aws_region, aws_id, aws_secret, aws_token
595
+ end
596
+
597
+ end
598
+
599
+
600
+ end
601
+ end