vagrant-aws-stsmith 0.5.0.dev

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.
Files changed (38) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +21 -0
  3. data/CHANGELOG.md +76 -0
  4. data/Gemfile +10 -0
  5. data/LICENSE +8 -0
  6. data/README.md +251 -0
  7. data/Rakefile +21 -0
  8. data/dummy.box +0 -0
  9. data/example_box/README.md +13 -0
  10. data/example_box/metadata.json +3 -0
  11. data/lib/vagrant-aws.rb +18 -0
  12. data/lib/vagrant-aws/action.rb +190 -0
  13. data/lib/vagrant-aws/action/connect_aws.rb +46 -0
  14. data/lib/vagrant-aws/action/is_created.rb +18 -0
  15. data/lib/vagrant-aws/action/is_stopped.rb +18 -0
  16. data/lib/vagrant-aws/action/message_already_created.rb +16 -0
  17. data/lib/vagrant-aws/action/message_not_created.rb +16 -0
  18. data/lib/vagrant-aws/action/message_will_not_destroy.rb +16 -0
  19. data/lib/vagrant-aws/action/read_ssh_info.rb +53 -0
  20. data/lib/vagrant-aws/action/read_state.rb +38 -0
  21. data/lib/vagrant-aws/action/run_instance.rb +247 -0
  22. data/lib/vagrant-aws/action/start_instance.rb +81 -0
  23. data/lib/vagrant-aws/action/stop_instance.rb +28 -0
  24. data/lib/vagrant-aws/action/sync_folders.rb +118 -0
  25. data/lib/vagrant-aws/action/terminate_instance.rb +47 -0
  26. data/lib/vagrant-aws/action/timed_provision.rb +21 -0
  27. data/lib/vagrant-aws/action/wait_for_state.rb +41 -0
  28. data/lib/vagrant-aws/action/warn_networks.rb +19 -0
  29. data/lib/vagrant-aws/config.rb +372 -0
  30. data/lib/vagrant-aws/errors.rb +31 -0
  31. data/lib/vagrant-aws/plugin.rb +73 -0
  32. data/lib/vagrant-aws/provider.rb +50 -0
  33. data/lib/vagrant-aws/util/timer.rb +17 -0
  34. data/lib/vagrant-aws/version.rb +5 -0
  35. data/locales/en.yml +122 -0
  36. data/spec/vagrant-aws/config_spec.rb +216 -0
  37. data/vagrant-aws.gemspec +59 -0
  38. metadata +149 -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,118 @@
1
+ require "log4r"
2
+
3
+ require "vagrant/util/subprocess"
4
+
5
+ require "vagrant/util/scoped_hash_override"
6
+
7
+ require "vagrant/util/which"
8
+
9
+ module VagrantPlugins
10
+ module AWS
11
+ module Action
12
+ # This middleware uses `rsync` to sync the folders over to the
13
+ # AWS instance.
14
+ class SyncFolders
15
+ include Vagrant::Util::ScopedHashOverride
16
+
17
+ def initialize(app, env)
18
+ @app = app
19
+ @logger = Log4r::Logger.new("vagrant_aws::action::sync_folders")
20
+ end
21
+
22
+ def call(env)
23
+ @app.call(env)
24
+
25
+ ssh_info = env[:machine].ssh_info
26
+
27
+ unless Vagrant::Util::Which.which('rsync')
28
+ env[:ui].warn(I18n.t('vagrant_aws.rsync_not_found_warning', :side => "host"))
29
+ return
30
+ end
31
+
32
+ if env[:machine].communicate.execute('which rsync', :error_check => false) != 0
33
+ env[:ui].warn(I18n.t('vagrant_aws.rsync_not_found_warning', :side => "guest"))
34
+ return
35
+ end
36
+
37
+ env[:machine].config.vm.synced_folders.each do |id, data|
38
+ data = scoped_hash_override(data, :aws)
39
+
40
+ # Ignore disabled shared folders
41
+ next if data[:disabled]
42
+
43
+ hostpath = File.expand_path(data[:hostpath], env[:root_path])
44
+ guestpath = data[:guestpath]
45
+
46
+ # Make sure there is a trailing slash on the host path to
47
+ # avoid creating an additional directory with rsync
48
+ hostpath = "#{hostpath}/" if hostpath !~ /\/$/
49
+
50
+ # on windows rsync.exe requires cygdrive-style paths
51
+ if Vagrant::Util::Platform.windows?
52
+ hostpath = hostpath.gsub(/^(\w):/) { "/cygdrive/#{$1}" }
53
+ end
54
+
55
+ env[:ui].info(I18n.t("vagrant_aws.rsync_folder",
56
+ :hostpath => hostpath,
57
+ :guestpath => guestpath))
58
+
59
+ # Create the host path if it doesn't exist and option flag is set
60
+ if data[:create]
61
+ begin
62
+ FileUtils::mkdir_p(hostpath)
63
+ rescue => err
64
+ raise Errors::MkdirError,
65
+ :hostpath => hostpath,
66
+ :err => err
67
+ end
68
+ end
69
+
70
+ # Create the guest path
71
+ env[:machine].communicate.sudo("mkdir -p '#{guestpath}'")
72
+ env[:machine].communicate.sudo(
73
+ "chown -R #{ssh_info[:username]} '#{guestpath}'")
74
+
75
+ #collect rsync excludes specified :rsync_excludes=>['path1',...] in synced_folder options
76
+ excludes = ['.vagrant/', 'Vagrantfile', *Array(data[:rsync_excludes])].uniq
77
+
78
+ ssh_options = ["StrictHostKeyChecking=no"]
79
+ # Use proxy command if it's set
80
+ if ssh_info[:proxy_command]
81
+ ssh_options.push("ProxyCommand #{ssh_info[:proxy_command]}")
82
+ end
83
+
84
+ # Rsync over to the guest path using the SSH info
85
+ command = [
86
+ "rsync", "--verbose", "--archive", "-z",
87
+ *excludes.map{|e|['--exclude', e]}.flatten,
88
+ "-e", "ssh -p #{ssh_info[:port]} #{ssh_key_options(ssh_info)} " +
89
+ ssh_options.map { |ssh_option| "-o '#{ssh_option}' " }.join,
90
+ hostpath,
91
+ "#{ssh_info[:username]}@#{ssh_info[:host]}:#{guestpath}"]
92
+
93
+ # we need to fix permissions when using rsync.exe on windows, see
94
+ # http://stackoverflow.com/questions/5798807/rsync-permission-denied-created-directories-have-no-permissions
95
+ if Vagrant::Util::Platform.windows?
96
+ command.insert(1, "--chmod", "ugo=rwX")
97
+ end
98
+
99
+ r = Vagrant::Util::Subprocess.execute(*command)
100
+ if r.exit_code != 0
101
+ raise Errors::RsyncError,
102
+ :guestpath => guestpath,
103
+ :hostpath => hostpath,
104
+ :stderr => r.stderr
105
+ end
106
+ end
107
+ end
108
+
109
+ private
110
+
111
+ def ssh_key_options(ssh_info)
112
+ # Ensure that `private_key_path` is an Array (for Vagrant < 1.4)
113
+ Array(ssh_info[:private_key_path]).map { |path| "-i '#{path}' " }.join
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,47 @@
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
+
17
+ # Release the elastic IP
18
+ ip_file = env[:machine].data_dir.join('elastic_ip')
19
+ if ip_file.file?
20
+ release_address(env,ip_file.read)
21
+ ip_file.delete
22
+ end
23
+
24
+ # Destroy the server and remove the tracking ID
25
+ env[:ui].info(I18n.t("vagrant_aws.terminating"))
26
+ server.destroy
27
+ env[:machine].id = nil
28
+
29
+ @app.call(env)
30
+ end
31
+
32
+ # Release an elastic IP address
33
+ def release_address(env,eip)
34
+ h = JSON.parse(eip)
35
+ # Use association_id and allocation_id for VPC, use public IP for EC2
36
+ if h['association_id']
37
+ env[:aws_compute].disassociate_address(nil,h['association_id'])
38
+ env[:aws_compute].release_address(h['allocation_id'])
39
+ else
40
+ env[:aws_compute].disassociate_address(h['public_ip'])
41
+ env[:aws_compute].release_address(h['public_ip'])
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ 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,372 @@
1
+ require "vagrant"
2
+
3
+ module VagrantPlugins
4
+ module AWS
5
+ class Config < Vagrant.plugin("2", :config)
6
+ # The access key ID for accessing AWS.
7
+ #
8
+ # @return [String]
9
+ attr_accessor :access_key_id
10
+
11
+ # The ID of the AMI to use.
12
+ #
13
+ # @return [String]
14
+ attr_accessor :ami
15
+
16
+ # The availability zone to launch the instance into. If nil, it will
17
+ # use the default for your account.
18
+ #
19
+ # @return [String]
20
+ attr_accessor :availability_zone
21
+
22
+ # The timeout to wait for an instance to become ready.
23
+ #
24
+ # @return [Fixnum]
25
+ attr_accessor :instance_ready_timeout
26
+
27
+ # The type of instance to launch, such as "m1.small"
28
+ #
29
+ # @return [String]
30
+ attr_accessor :instance_type
31
+
32
+ # The name of the keypair to use.
33
+ #
34
+ # @return [String]
35
+ attr_accessor :keypair_name
36
+
37
+ # The private IP address to give this machine (VPC).
38
+ #
39
+ # @return [String]
40
+ attr_accessor :private_ip_address
41
+
42
+ # Acquire and attach an elastic IP address (VPC).
43
+ #
44
+ # @return [Boolean]
45
+ attr_accessor :elastic_ip
46
+
47
+ # The name of the AWS region in which to create the instance.
48
+ #
49
+ # @return [String]
50
+ attr_accessor :region
51
+
52
+ # The EC2 endpoint to connect to
53
+ #
54
+ # @return [String]
55
+ attr_accessor :endpoint
56
+
57
+ # The version of the AWS api to use
58
+ #
59
+ # @return [String]
60
+ attr_accessor :version
61
+
62
+ # The secret access key for accessing AWS.
63
+ #
64
+ # @return [String]
65
+ attr_accessor :secret_access_key
66
+
67
+ # The security groups to set on the instance. For VPC this must
68
+ # be a list of IDs. For EC2, it can be either.
69
+ #
70
+ # @return [Array<String>]
71
+ attr_reader :security_groups
72
+
73
+ # The Amazon resource name (ARN) of the IAM Instance Profile
74
+ # to associate with the instance.
75
+ #
76
+ # @return [String]
77
+ attr_accessor :iam_instance_profile_arn
78
+
79
+ # The name of the IAM Instance Profile to associate with
80
+ # the instance.
81
+ #
82
+ # @return [String]
83
+ attr_accessor :iam_instance_profile_name
84
+
85
+ # The subnet ID to launch the machine into (VPC).
86
+ #
87
+ # @return [String]
88
+ attr_accessor :subnet_id
89
+
90
+ # The tags for the machine.
91
+ #
92
+ # @return [Hash<String, String>]
93
+ attr_accessor :tags
94
+
95
+ # Use IAM Instance Role for authentication to AWS instead of an
96
+ # explicit access_id and secret_access_key
97
+ #
98
+ # @return [Boolean]
99
+ attr_accessor :use_iam_profile
100
+
101
+ # The user data string
102
+ #
103
+ # @return [String]
104
+ attr_accessor :user_data
105
+
106
+ # Block device mappings
107
+ #
108
+ # @return [Array<Hash>]
109
+ attr_accessor :block_device_mapping
110
+
111
+ # Indicates whether an instance stops or terminates when you initiate shutdown from the instance
112
+ #
113
+ # @return [bool]
114
+ attr_accessor :terminate_on_shutdown
115
+
116
+ # Specifies which address to connect to with ssh
117
+ # Must be one of:
118
+ # - :public_ip_address
119
+ # - :dns_name
120
+ # - :private_ip_address
121
+ # This attribute also accepts an array of symbols
122
+ #
123
+ # @return [Symbol]
124
+ attr_accessor :ssh_host_attribute
125
+
126
+ # Enables Monitoring
127
+ #
128
+ # @return [Boolean]
129
+ attr_accessor :monitoring
130
+
131
+ # EBS optimized instance
132
+ #
133
+ # @return [Boolean]
134
+ attr_accessor :ebs_optimized
135
+
136
+ # Assigning a public IP address in a VPC
137
+ #
138
+ # @return [Boolean]
139
+ attr_accessor :associate_public_ip
140
+
141
+ def initialize(region_specific=false)
142
+ @access_key_id = UNSET_VALUE
143
+ @ami = UNSET_VALUE
144
+ @availability_zone = UNSET_VALUE
145
+ @instance_ready_timeout = UNSET_VALUE
146
+ @instance_type = UNSET_VALUE
147
+ @keypair_name = UNSET_VALUE
148
+ @private_ip_address = UNSET_VALUE
149
+ @region = UNSET_VALUE
150
+ @endpoint = UNSET_VALUE
151
+ @version = UNSET_VALUE
152
+ @secret_access_key = UNSET_VALUE
153
+ @security_groups = UNSET_VALUE
154
+ @subnet_id = UNSET_VALUE
155
+ @tags = {}
156
+ @user_data = UNSET_VALUE
157
+ @use_iam_profile = UNSET_VALUE
158
+ @block_device_mapping = []
159
+ @elastic_ip = UNSET_VALUE
160
+ @iam_instance_profile_arn = UNSET_VALUE
161
+ @iam_instance_profile_name = UNSET_VALUE
162
+ @terminate_on_shutdown = UNSET_VALUE
163
+ @ssh_host_attribute = UNSET_VALUE
164
+ @monitoring = UNSET_VALUE
165
+ @ebs_optimized = UNSET_VALUE
166
+ @associate_public_ip = UNSET_VALUE
167
+
168
+ # Internal state (prefix with __ so they aren't automatically
169
+ # merged)
170
+ @__compiled_region_configs = {}
171
+ @__finalized = false
172
+ @__region_config = {}
173
+ @__region_specific = region_specific
174
+ end
175
+
176
+ # set security_groups
177
+ def security_groups=(value)
178
+ # convert value to array if necessary
179
+ @security_groups = value.is_a?(Array) ? value : [value]
180
+ end
181
+
182
+ # Allows region-specific overrides of any of the settings on this
183
+ # configuration object. This allows the user to override things like
184
+ # AMI and keypair name for regions. Example:
185
+ #
186
+ # aws.region_config "us-east-1" do |region|
187
+ # region.ami = "ami-12345678"
188
+ # region.keypair_name = "company-east"
189
+ # end
190
+ #
191
+ # @param [String] region The region name to configure.
192
+ # @param [Hash] attributes Direct attributes to set on the configuration
193
+ # as a shortcut instead of specifying a full block.
194
+ # @yield [config] Yields a new AWS configuration.
195
+ def region_config(region, attributes=nil, &block)
196
+ # Append the block to the list of region configs for that region.
197
+ # We'll evaluate these upon finalization.
198
+ @__region_config[region] ||= []
199
+
200
+ # Append a block that sets attributes if we got one
201
+ if attributes
202
+ attr_block = lambda do |config|
203
+ config.set_options(attributes)
204
+ end
205
+
206
+ @__region_config[region] << attr_block
207
+ end
208
+
209
+ # Append a block if we got one
210
+ @__region_config[region] << block if block_given?
211
+ end
212
+
213
+ #-------------------------------------------------------------------
214
+ # Internal methods.
215
+ #-------------------------------------------------------------------
216
+
217
+ def merge(other)
218
+ super.tap do |result|
219
+ # Copy over the region specific flag. "True" is retained if either
220
+ # has it.
221
+ new_region_specific = other.instance_variable_get(:@__region_specific)
222
+ result.instance_variable_set(
223
+ :@__region_specific, new_region_specific || @__region_specific)
224
+
225
+ # Go through all the region configs and prepend ours onto
226
+ # theirs.
227
+ new_region_config = other.instance_variable_get(:@__region_config)
228
+ @__region_config.each do |key, value|
229
+ new_region_config[key] ||= []
230
+ new_region_config[key] = value + new_region_config[key]
231
+ end
232
+
233
+ # Set it
234
+ result.instance_variable_set(:@__region_config, new_region_config)
235
+
236
+ # Merge in the tags
237
+ result.tags.merge!(self.tags)
238
+ result.tags.merge!(other.tags)
239
+
240
+ # Merge block_device_mapping
241
+ result.block_device_mapping |= self.block_device_mapping
242
+ result.block_device_mapping |= other.block_device_mapping
243
+ end
244
+ end
245
+
246
+ def finalize!
247
+ # Try to get access keys from standard AWS environment variables; they
248
+ # will default to nil if the environment variables are not present.
249
+ @access_key_id = ENV['AWS_ACCESS_KEY'] if @access_key_id == UNSET_VALUE
250
+ @secret_access_key = ENV['AWS_SECRET_KEY'] if @secret_access_key == UNSET_VALUE
251
+
252
+ # AMI must be nil, since we can't default that
253
+ @ami = nil if @ami == UNSET_VALUE
254
+
255
+ # Set the default timeout for waiting for an instance to be ready
256
+ @instance_ready_timeout = 120 if @instance_ready_timeout == UNSET_VALUE
257
+
258
+ # Default instance type is an m1.small
259
+ @instance_type = "m1.small" if @instance_type == UNSET_VALUE
260
+
261
+ # Keypair defaults to nil
262
+ @keypair_name = nil if @keypair_name == UNSET_VALUE
263
+
264
+ # Default the private IP to nil since VPC is not default
265
+ @private_ip_address = nil if @private_ip_address == UNSET_VALUE
266
+
267
+ # Acquire an elastic IP if requested
268
+ @elastic_ip = nil if @elastic_ip == UNSET_VALUE
269
+
270
+ # Default region is us-east-1. This is sensible because AWS
271
+ # generally defaults to this as well.
272
+ @region = "us-east-1" if @region == UNSET_VALUE
273
+ @availability_zone = nil if @availability_zone == UNSET_VALUE
274
+ @endpoint = nil if @endpoint == UNSET_VALUE
275
+ @version = nil if @version == UNSET_VALUE
276
+
277
+ # The security groups are empty by default.
278
+ @security_groups = [] if @security_groups == UNSET_VALUE
279
+
280
+ # Subnet is nil by default otherwise we'd launch into VPC.
281
+ @subnet_id = nil if @subnet_id == UNSET_VALUE
282
+
283
+ # IAM Instance profile arn/name is nil by default.
284
+ @iam_instance_profile_arn = nil if @iam_instance_profile_arn == UNSET_VALUE
285
+ @iam_instance_profile_name = nil if @iam_instance_profile_name == UNSET_VALUE
286
+
287
+ # By default we don't use an IAM profile
288
+ @use_iam_profile = false if @use_iam_profile == UNSET_VALUE
289
+
290
+ # User Data is nil by default
291
+ @user_data = nil if @user_data == UNSET_VALUE
292
+
293
+ # default false
294
+ @terminate_on_shutdown = false if @terminate_on_shutdown == UNSET_VALUE
295
+
296
+ # default to nil
297
+ @ssh_host_attribute = nil if @ssh_host_attribute == UNSET_VALUE
298
+
299
+ # default false
300
+ @monitoring = false if @monitoring == UNSET_VALUE
301
+
302
+ # default false
303
+ @ebs_optimized = false if @ebs_optimized == UNSET_VALUE
304
+
305
+ # default false
306
+ @associate_public_ip = false if @associate_public_ip == UNSET_VALUE
307
+
308
+ # Compile our region specific configurations only within
309
+ # NON-REGION-SPECIFIC configurations.
310
+ if !@__region_specific
311
+ @__region_config.each do |region, blocks|
312
+ config = self.class.new(true).merge(self)
313
+
314
+ # Execute the configuration for each block
315
+ blocks.each { |b| b.call(config) }
316
+
317
+ # The region name of the configuration always equals the
318
+ # region config name:
319
+ config.region = region
320
+
321
+ # Finalize the configuration
322
+ config.finalize!
323
+
324
+ # Store it for retrieval
325
+ @__compiled_region_configs[region] = config
326
+ end
327
+ end
328
+
329
+ # Mark that we finalized
330
+ @__finalized = true
331
+ end
332
+
333
+ def validate(machine)
334
+ errors = _detected_errors
335
+
336
+ errors << I18n.t("vagrant_aws.config.region_required") if @region.nil?
337
+
338
+ if @region
339
+ # Get the configuration for the region we're using and validate only
340
+ # that region.
341
+ config = get_region_config(@region)
342
+
343
+ if !config.use_iam_profile
344
+ errors << I18n.t("vagrant_aws.config.access_key_id_required") if \
345
+ config.access_key_id.nil?
346
+ errors << I18n.t("vagrant_aws.config.secret_access_key_required") if \
347
+ config.secret_access_key.nil?
348
+ end
349
+
350
+ if config.associate_public_ip && !subnet_id
351
+ errors << I18n.t("vagrant_aws.config.subnet_id_required_with_public_ip")
352
+ end
353
+
354
+ errors << I18n.interpolate("vagrant_aws.config.ami_required", :region => @region) if config.ami.nil?
355
+ end
356
+
357
+ { "AWS Provider" => errors }
358
+ end
359
+
360
+ # This gets the configuration for a specific region. It shouldn't
361
+ # be called by the general public and is only used internally.
362
+ def get_region_config(name)
363
+ if !@__finalized
364
+ raise "Configuration must be finalized before calling this method."
365
+ end
366
+
367
+ # Return the compiled region config
368
+ @__compiled_region_configs[name] || self
369
+ end
370
+ end
371
+ end
372
+ end