vagrant-mos 0.8.39

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +3 -0
  3. data/CHANGELOG.md +92 -0
  4. data/Gemfile +12 -0
  5. data/LICENSE +8 -0
  6. data/README.md +292 -0
  7. data/Rakefile +21 -0
  8. data/Vagrantfile +1 -0
  9. data/dummy.box +0 -0
  10. data/example_box/README.md +13 -0
  11. data/example_box/Vagrantfile +8 -0
  12. data/example_box/metadata.json +3 -0
  13. data/lib/vagrant-mos.rb +18 -0
  14. data/lib/vagrant-mos/action.rb +212 -0
  15. data/lib/vagrant-mos/action/connect_mos.rb +51 -0
  16. data/lib/vagrant-mos/action/elb_deregister_instance.rb +24 -0
  17. data/lib/vagrant-mos/action/elb_register_instance.rb +24 -0
  18. data/lib/vagrant-mos/action/is_created.rb +18 -0
  19. data/lib/vagrant-mos/action/is_stopped.rb +19 -0
  20. data/lib/vagrant-mos/action/message_already_created.rb +16 -0
  21. data/lib/vagrant-mos/action/message_not_created.rb +16 -0
  22. data/lib/vagrant-mos/action/message_will_not_destroy.rb +16 -0
  23. data/lib/vagrant-mos/action/package_instance.rb +192 -0
  24. data/lib/vagrant-mos/action/read_ssh_info.rb +64 -0
  25. data/lib/vagrant-mos/action/read_state.rb +46 -0
  26. data/lib/vagrant-mos/action/run_instance.rb +287 -0
  27. data/lib/vagrant-mos/action/start_instance.rb +82 -0
  28. data/lib/vagrant-mos/action/stop_instance.rb +29 -0
  29. data/lib/vagrant-mos/action/terminate_instance.rb +52 -0
  30. data/lib/vagrant-mos/action/timed_provision.rb +21 -0
  31. data/lib/vagrant-mos/action/wait_for_state.rb +41 -0
  32. data/lib/vagrant-mos/action/warn_networks.rb +19 -0
  33. data/lib/vagrant-mos/config.rb +405 -0
  34. data/lib/vagrant-mos/errors.rb +43 -0
  35. data/lib/vagrant-mos/plugin.rb +73 -0
  36. data/lib/vagrant-mos/provider.rb +53 -0
  37. data/lib/vagrant-mos/util/elb.rb +56 -0
  38. data/lib/vagrant-mos/util/timer.rb +17 -0
  39. data/lib/vagrant-mos/version.rb +5 -0
  40. data/locales/en.yml +153 -0
  41. data/mos.box +0 -0
  42. data/spec/spec_helper.rb +1 -0
  43. data/spec/vagrant-mos/config_spec.rb +225 -0
  44. data/templates/metadata.json.erb +3 -0
  45. data/templates/vagrant-aws_package_Vagrantfile.erb +5 -0
  46. data/vagrant-mos.gemspec +60 -0
  47. metadata +172 -0
@@ -0,0 +1,82 @@
1
+ require "log4r"
2
+
3
+ require 'vagrant/util/retryable'
4
+
5
+ require 'vagrant-mos/util/timer'
6
+
7
+ module VagrantPlugins
8
+ module MOS
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_mos::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[:mos_compute].servers.get(env[:machine].id)
24
+ server = (env[:mos_compute].describe_instances([env[:machine].id]))["Instance"]
25
+ env[:ui].info(I18n.t("vagrant_mos.starting"))
26
+
27
+ begin
28
+ #server.start
29
+ env[:mos_compute].start_instance(env[:machine].id)
30
+
31
+ region = env[:machine].provider_config.region
32
+ region_config = env[:machine].provider_config.get_region_config(region)
33
+
34
+ # Wait for the instance to be ready first
35
+ env[:metrics]["instance_ready_time"] = Util::Timer.time do
36
+ tries = region_config.instance_ready_timeout / 2
37
+
38
+ env[:ui].info(I18n.t("vagrant_mos.waiting_for_ready"))
39
+ #begin
40
+ # retryable(:on => Fog::Errors::TimeoutError, :tries => tries) do
41
+ # # If we're interrupted don't worry about waiting
42
+ # next if env[:interrupted]
43
+ #
44
+ # # Wait for the server to be ready
45
+ # #server.wait_for(2) { ready? }
46
+ # end
47
+ #rescue Fog::Errors::TimeoutError
48
+ # # Notify the user
49
+ # raise Errors::InstanceReadyTimeout,
50
+ # timeout: region_config.instance_ready_timeout
51
+ #end
52
+ end
53
+ rescue Fog::Compute::MOS::Error => e
54
+ raise Errors::FogError, :message => e.message
55
+ end
56
+
57
+ @logger.info("Time to instance ready: #{env[:metrics]["instance_ready_time"]}")
58
+
59
+ if !env[:interrupted]
60
+ env[:metrics]["instance_ssh_time"] = Util::Timer.time do
61
+ # Wait for SSH to be ready.
62
+ env[:ui].info(I18n.t("vagrant_mos.waiting_for_ssh"))
63
+ while true
64
+ # If we're interrupted then just back out
65
+ break if env[:interrupted]
66
+ break if env[:machine].communicate.ready?
67
+ sleep 2
68
+ end
69
+ end
70
+
71
+ @logger.info("Time for SSH ready: #{env[:metrics]["instance_ssh_time"]}")
72
+
73
+ # Ready and booted!
74
+ env[:ui].info(I18n.t("vagrant_mos.ready"))
75
+ end
76
+
77
+ @app.call(env)
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,29 @@
1
+ require "log4r"
2
+
3
+ module VagrantPlugins
4
+ module MOS
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_mos::action::stop_instance")
11
+ end
12
+
13
+ def call(env)
14
+ #server = env[:mos_compute].servers.get(env[:machine].id)
15
+ #server = (env[:mos_compute].describe_instances([env[:machine].id]))["Instance"]
16
+ if env[:machine].state.id == "ready"
17
+ env[:ui].info(I18n.t("vagrant_mos.already stopped"))
18
+ else
19
+ env[:ui].info(I18n.t("vagrant_mos.stopping"))
20
+ #server.stop(!!env[:force_halt])
21
+ env[:mos_compute].stop_instance(env[:machine].id)
22
+ end
23
+
24
+ @app.call(env)
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,52 @@
1
+ require "log4r"
2
+ require "json"
3
+
4
+ module VagrantPlugins
5
+ module MOS
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_mos::action::terminate_instance")
12
+ end
13
+
14
+ def call(env)
15
+ server = env[:mos_compute].describe_instances(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_mos.terminating"))
30
+ #server.destroy
31
+ env[:mos_compute].terminate_instance(env[:machine].id)
32
+ env[:machine].id = nil
33
+
34
+ @app.call(env)
35
+ end
36
+
37
+ # Release an elastic IP address
38
+ def release_address(env,eip)
39
+ h = JSON.parse(eip)
40
+ # Use association_id and allocation_id for VPC, use public IP for EC2
41
+ if h['association_id']
42
+ env[:mos_compute].disassociate_address(nil,h['association_id'])
43
+ env[:mos_compute].release_address(h['allocation_id'])
44
+ else
45
+ env[:mos_compute].disassociate_address(h['public_ip'])
46
+ env[:mos_compute].release_address(h['public_ip'])
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,21 @@
1
+ require "vagrant-mos/util/timer"
2
+
3
+ module VagrantPlugins
4
+ module MOS
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 MOS
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_mos::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_mos.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 MOS
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_mos.warn_networks"))
12
+ end
13
+
14
+ @app.call(env)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,405 @@
1
+ require "vagrant"
2
+
3
+ module VagrantPlugins
4
+ module MOS
5
+ class Config < Vagrant.plugin("2", :config)
6
+ # The access key ID for accessing MOS.
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 timeout to wait for an instance to successfully burn into an AMI.
28
+ #
29
+ # @return [Fixnum]
30
+ attr_accessor :instance_package_timeout
31
+
32
+ # The type of instance to launch, such as "m3.medium"
33
+ #
34
+ # @return [String]
35
+ attr_accessor :instance_type
36
+
37
+ # The name of the keypair to use.
38
+ #
39
+ # @return [String]
40
+ attr_accessor :keypair_name
41
+
42
+ # The private IP address to give this machine (VPC).
43
+ #
44
+ # @return [String]
45
+ attr_accessor :private_ip_address
46
+
47
+ # If true, acquire and attach an elastic IP address.
48
+ # If set to an IP address, assign to the instance.
49
+ #
50
+ # @return [String]
51
+ attr_accessor :elastic_ip
52
+
53
+ # The name of the MOS region in which to create the instance.
54
+ #
55
+ # @return [String]
56
+ attr_accessor :region
57
+
58
+ # The EC2 endpoint to connect to
59
+ #
60
+ # @return [String]
61
+ attr_accessor :endpoint
62
+
63
+ # The version of the MOS api to use
64
+ #
65
+ # @return [String]
66
+ attr_accessor :version
67
+
68
+ # The secret access key for accessing MOS.
69
+ #
70
+ # @return [String]
71
+ attr_accessor :secret_access_key
72
+
73
+ # The secret access url for accessing MOS.
74
+ #
75
+ # @return [String]
76
+ attr_accessor :secret_access_url
77
+
78
+ # The token associated with the key for accessing MOS.
79
+ #
80
+ # @return [String]
81
+ attr_accessor :session_token
82
+
83
+ # The security groups to set on the instance. For VPC this must
84
+ # be a list of IDs. For EC2, it can be either.
85
+ #
86
+ # @return [Array<String>]
87
+ attr_reader :security_groups
88
+
89
+ # The Amazon resource name (ARN) of the IAM Instance Profile
90
+ # to associate with the instance.
91
+ #
92
+ # @return [String]
93
+ attr_accessor :iam_instance_profile_arn
94
+
95
+ # The name of the IAM Instance Profile to associate with
96
+ # the instance.
97
+ #
98
+ # @return [String]
99
+ attr_accessor :iam_instance_profile_name
100
+
101
+ # The subnet ID to launch the machine into (VPC).
102
+ #
103
+ # @return [String]
104
+ attr_accessor :subnet_id
105
+
106
+ # The tags for the machine.
107
+ #
108
+ # @return [Hash<String, String>]
109
+ attr_accessor :tags
110
+
111
+ # Use IAM Instance Role for authentication to MOS instead of an
112
+ # explicit access_id and secret_access_key
113
+ #
114
+ # @return [Boolean]
115
+ attr_accessor :use_iam_profile
116
+
117
+ # The user data string
118
+ #
119
+ # @return [String]
120
+ attr_accessor :user_data
121
+
122
+ # Block device mappings
123
+ #
124
+ # @return [Array<Hash>]
125
+ attr_accessor :block_device_mapping
126
+
127
+ # Indicates whether an instance stops or terminates when you initiate shutdown from the instance
128
+ #
129
+ # @return [bool]
130
+ attr_accessor :terminate_on_shutdown
131
+
132
+ # Specifies which address to connect to with ssh
133
+ # Must be one of:
134
+ # - :public_ip_address
135
+ # - :dns_name
136
+ # - :private_ip_address
137
+ # This attribute also accepts an array of symbols
138
+ #
139
+ # @return [Symbol]
140
+ attr_accessor :ssh_host_attribute
141
+
142
+ # Enables Monitoring
143
+ #
144
+ # @return [Boolean]
145
+ attr_accessor :monitoring
146
+
147
+ # EBS optimized instance
148
+ #
149
+ # @return [Boolean]
150
+ attr_accessor :ebs_optimized
151
+
152
+ # Assigning a public IP address in a VPC
153
+ #
154
+ # @return [Boolean]
155
+ attr_accessor :associate_public_ip
156
+
157
+ # The name of ELB, which an instance should be
158
+ # attached to
159
+ #
160
+ # @return [String]
161
+ attr_accessor :elb
162
+
163
+ def initialize(region_specific=false)
164
+ @access_key_id = UNSET_VALUE
165
+ @ami = UNSET_VALUE
166
+ @availability_zone = UNSET_VALUE
167
+ @instance_ready_timeout = UNSET_VALUE
168
+ @instance_package_timeout = UNSET_VALUE
169
+ @instance_type = UNSET_VALUE
170
+ @keypair_name = UNSET_VALUE
171
+ @private_ip_address = UNSET_VALUE
172
+ @region = UNSET_VALUE
173
+ @endpoint = UNSET_VALUE
174
+ @version = UNSET_VALUE
175
+ @secret_access_key = UNSET_VALUE
176
+ @secret_access_url = UNSET_VALUE
177
+ @session_token = UNSET_VALUE
178
+ @security_groups = UNSET_VALUE
179
+ @subnet_id = UNSET_VALUE
180
+ @tags = {}
181
+ @user_data = UNSET_VALUE
182
+ @use_iam_profile = UNSET_VALUE
183
+ @block_device_mapping = []
184
+ @elastic_ip = UNSET_VALUE
185
+ @iam_instance_profile_arn = UNSET_VALUE
186
+ @iam_instance_profile_name = UNSET_VALUE
187
+ @terminate_on_shutdown = UNSET_VALUE
188
+ @ssh_host_attribute = UNSET_VALUE
189
+ @monitoring = UNSET_VALUE
190
+ @ebs_optimized = UNSET_VALUE
191
+ @associate_public_ip = UNSET_VALUE
192
+ @elb = UNSET_VALUE
193
+
194
+ # Internal state (prefix with __ so they aren't automatically
195
+ # merged)
196
+ @__compiled_region_configs = {}
197
+ @__finalized = false
198
+ @__region_config = {}
199
+ @__region_specific = region_specific
200
+ end
201
+
202
+ # set security_groups
203
+ def security_groups=(value)
204
+ # convert value to array if necessary
205
+ @security_groups = value.is_a?(Array) ? value : [value]
206
+ end
207
+
208
+ # Allows region-specific overrides of any of the settings on this
209
+ # configuration object. This allows the user to override things like
210
+ # AMI and keypair name for regions. Example:
211
+ #
212
+ # mos.region_config "us-east-1" do |region|
213
+ # region.ami = "ami-12345678"
214
+ # region.keypair_name = "company-east"
215
+ # end
216
+ #
217
+ # @param [String] region The region name to configure.
218
+ # @param [Hash] attributes Direct attributes to set on the configuration
219
+ # as a shortcut instead of specifying a full block.
220
+ # @yield [config] Yields a new MOS configuration.
221
+ def region_config(region, attributes=nil, &block)
222
+ # Append the block to the list of region configs for that region.
223
+ # We'll evaluate these upon finalization.
224
+ @__region_config[region] ||= []
225
+
226
+ # Append a block that sets attributes if we got one
227
+ if attributes
228
+ attr_block = lambda do |config|
229
+ config.set_options(attributes)
230
+ end
231
+
232
+ @__region_config[region] << attr_block
233
+ end
234
+
235
+ # Append a block if we got one
236
+ @__region_config[region] << block if block_given?
237
+ end
238
+
239
+ #-------------------------------------------------------------------
240
+ # Internal methods.
241
+ #-------------------------------------------------------------------
242
+
243
+ def merge(other)
244
+ super.tap do |result|
245
+ # Copy over the region specific flag. "True" is retained if either
246
+ # has it.
247
+ new_region_specific = other.instance_variable_get(:@__region_specific)
248
+ result.instance_variable_set(
249
+ :@__region_specific, new_region_specific || @__region_specific)
250
+
251
+ # Go through all the region configs and prepend ours onto
252
+ # theirs.
253
+ new_region_config = other.instance_variable_get(:@__region_config)
254
+ @__region_config.each do |key, value|
255
+ new_region_config[key] ||= []
256
+ new_region_config[key] = value + new_region_config[key]
257
+ end
258
+
259
+ # Set it
260
+ result.instance_variable_set(:@__region_config, new_region_config)
261
+
262
+ # Merge in the tags
263
+ result.tags.merge!(self.tags)
264
+ result.tags.merge!(other.tags)
265
+
266
+ # Merge block_device_mapping
267
+ result.block_device_mapping |= self.block_device_mapping
268
+ result.block_device_mapping |= other.block_device_mapping
269
+ end
270
+ end
271
+
272
+ def finalize!
273
+ # Try to get access keys from standard MOS environment variables; they
274
+ # will default to nil if the environment variables are not present.
275
+ @access_key_id = ENV['MOS_ACCESS_KEY'] if @access_key_id == UNSET_VALUE
276
+ @secret_access_key = ENV['MOS_SECRET_KEY'] if @secret_access_key == UNSET_VALUE
277
+ @session_token = ENV['MOS_SESSION_TOKEN'] if @session_token == UNSET_VALUE
278
+
279
+ # AMI must be nil, since we can't default that
280
+ @ami = nil if @ami == UNSET_VALUE
281
+
282
+ # Set the default timeout for waiting for an instance to be ready
283
+ @instance_ready_timeout = 120 if @instance_ready_timeout == UNSET_VALUE
284
+
285
+ # Set the default timeout for waiting for an instance to burn into and ami
286
+ @instance_package_timeout = 600 if @instance_package_timeout == UNSET_VALUE
287
+
288
+ # Default instance type is an m3.medium
289
+ #@instance_type = "m3.medium" if @instance_type == UNSET_VALUE
290
+ @instance_type = "C1_M2" if @instance_type == UNSET_VALUE
291
+ # Keypair defaults to nil
292
+ @keypair_name = nil if @keypair_name == UNSET_VALUE
293
+
294
+ # Default the private IP to nil since VPC is not default
295
+ @private_ip_address = nil if @private_ip_address == UNSET_VALUE
296
+
297
+ # Acquire an elastic IP if requested
298
+ @elastic_ip = nil if @elastic_ip == UNSET_VALUE
299
+
300
+ # Default region is us-east-1. This is sensible because MOS
301
+ # generally defaults to this as well.
302
+ @region = "us-east-1" if @region == UNSET_VALUE
303
+ @availability_zone = nil if @availability_zone == UNSET_VALUE
304
+ @endpoint = nil if @endpoint == UNSET_VALUE
305
+ @version = nil if @version == UNSET_VALUE
306
+
307
+ # The security groups are empty by default.
308
+ @security_groups = [] if @security_groups == UNSET_VALUE
309
+
310
+ # Subnet is nil by default otherwise we'd launch into VPC.
311
+ @subnet_id = nil if @subnet_id == UNSET_VALUE
312
+
313
+ # IAM Instance profile arn/name is nil by default.
314
+ @iam_instance_profile_arn = nil if @iam_instance_profile_arn == UNSET_VALUE
315
+ @iam_instance_profile_name = nil if @iam_instance_profile_name == UNSET_VALUE
316
+
317
+ # By default we don't use an IAM profile
318
+ @use_iam_profile = false if @use_iam_profile == UNSET_VALUE
319
+
320
+ # User Data is nil by default
321
+ @user_data = nil if @user_data == UNSET_VALUE
322
+
323
+ # default false
324
+ @terminate_on_shutdown = false if @terminate_on_shutdown == UNSET_VALUE
325
+
326
+ # default to nil
327
+ @ssh_host_attribute = nil if @ssh_host_attribute == UNSET_VALUE
328
+
329
+ # default false
330
+ @monitoring = false if @monitoring == UNSET_VALUE
331
+
332
+ # default false
333
+ @ebs_optimized = false if @ebs_optimized == UNSET_VALUE
334
+
335
+ # default false
336
+ @associate_public_ip = false if @associate_public_ip == UNSET_VALUE
337
+
338
+ # Don't attach instance to any ELB by default
339
+ @elb = nil if @elb == UNSET_VALUE
340
+
341
+ # Compile our region specific configurations only within
342
+ # NON-REGION-SPECIFIC configurations.
343
+ if !@__region_specific
344
+ @__region_config.each do |region, blocks|
345
+ config = self.class.new(true).merge(self)
346
+
347
+ # Execute the configuration for each block
348
+ blocks.each { |b| b.call(config) }
349
+
350
+ # The region name of the configuration always equals the
351
+ # region config name:
352
+ config.region = region
353
+
354
+ # Finalize the configuration
355
+ config.finalize!
356
+
357
+ # Store it for retrieval
358
+ @__compiled_region_configs[region] = config
359
+ end
360
+ end
361
+
362
+ # Mark that we finalized
363
+ @__finalized = true
364
+ end
365
+
366
+ def validate(machine)
367
+ errors = _detected_errors
368
+
369
+ errors << I18n.t("vagrant_mos.config.region_required") if @region.nil?
370
+
371
+ if @region
372
+ # Get the configuration for the region we're using and validate only
373
+ # that region.
374
+ config = get_region_config(@region)
375
+
376
+ if !config.use_iam_profile
377
+ errors << I18n.t("vagrant_mos.config.access_key_id_required") if \
378
+ config.access_key_id.nil?
379
+ errors << I18n.t("vagrant_mos.config.secret_access_key_required") if \
380
+ config.secret_access_key.nil?
381
+ end
382
+
383
+ if config.associate_public_ip && !config.subnet_id
384
+ errors << I18n.t("vagrant_mos.config.subnet_id_required_with_public_ip")
385
+ end
386
+
387
+ errors << I18n.interpolate("vagrant_mos.config.ami_required", :region => @region) if config.ami.nil?
388
+ end
389
+
390
+ { "MOS Provider" => errors }
391
+ end
392
+
393
+ # This gets the configuration for a specific region. It shouldn't
394
+ # be called by the general public and is only used internally.
395
+ def get_region_config(name)
396
+ if !@__finalized
397
+ raise "Configuration must be finalized before calling this method."
398
+ end
399
+
400
+ # Return the compiled region config
401
+ @__compiled_region_configs[name] || self
402
+ end
403
+ end
404
+ end
405
+ end