vagrant-aws 0.5.0 → 0.6.0

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: 6eb997239c2902fd5ffe82a2ad85f6a750b68fcc
4
- data.tar.gz: b4db22de6d6004ec60a2bd97f8bea1abe0b23ff8
3
+ metadata.gz: 8af2e697fcbbf3ff15a67a92539b492944ba5784
4
+ data.tar.gz: 3729da1381c5fed78328854b5a447d104fb82212
5
5
  SHA512:
6
- metadata.gz: 6a38047b88672ff53ff8002acaf948071bd020bac0e6cb4503291a1e10e2fb57406b4f6a6e1fadb63b5d1cfdf601b47b58bbb20191fe1d855a8748e0339422ad
7
- data.tar.gz: d93eca59839124a024b471430d8864b4aec2a5d2a8723e3ddb77d2a9babab505a478bc4517cc39db8bd82f1b16a00a238b15347a38d83bf42ae6914d4f57be6f
6
+ metadata.gz: 1f3c1b091c706c26507221206a92de3f8b7ba8d9f421c37de7164f84ed652838afa0d59127243e3ae863435a553c61f37b6bcd17d548c5c39946354b637fac53
7
+ data.tar.gz: 07c726e7633b5913e74d0e522044607253248d6bff1d00dde238f9d9ff54cd6764adc4c33dc3cce442d827dc48571a1c95c6b1774d144fe0b8884c5ac9deef9b
@@ -1,4 +1,8 @@
1
- # 0.5.0 (unreleased)
1
+ # 0.5.1
2
+
3
+ * Support static Elastic IP addresses.
4
+
5
+ # 0.5.0 (June 22, 2014)
2
6
 
3
7
  * Support for associating public IPs for VMs inside of VPCs (GH
4
8
  [#219](https://github.com/mitchellh/vagrant-aws/pull/219), GH
data/README.md CHANGED
@@ -1,4 +1,5 @@
1
1
  # Vagrant AWS Provider
2
+ [![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/mitchellh/vagrant-aws?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
2
3
 
3
4
  <span class="badges">
4
5
  [![Gem Version](https://badge.fury.io/rb/vagrant-aws.png)][gem]
@@ -20,8 +21,9 @@ EC2 and VPC.
20
21
  * SSH into the instances.
21
22
  * Provision the instances with any built-in Vagrant provisioner.
22
23
  * Minimal synced folder support via `rsync`.
23
- * Define region-specifc configurations so Vagrant can manage machines
24
+ * Define region-specific configurations so Vagrant can manage machines
24
25
  in multiple regions.
26
+ * Package running instances into new vagrant-aws friendly boxes
25
27
 
26
28
  ## Usage
27
29
 
@@ -61,6 +63,7 @@ Vagrant.configure("2") do |config|
61
63
  config.vm.provider :aws do |aws, override|
62
64
  aws.access_key_id = "YOUR KEY"
63
65
  aws.secret_access_key = "YOUR SECRET KEY"
66
+ aws.session_token = "SESSION TOKEN"
64
67
  aws.keypair_name = "KEYPAIR NAME"
65
68
 
66
69
  aws.ami = "ami-7747d01e"
@@ -105,17 +108,25 @@ This provider exposes quite a few provider-specific configuration options:
105
108
  the instance. If nil, it will use the default set by Amazon.
106
109
  * `instance_ready_timeout` - The number of seconds to wait for the instance
107
110
  to become "ready" in AWS. Defaults to 120 seconds.
108
- * `instance_type` - The type of instance, such as "m1.small". The default
109
- value of this if not specified is "m1.small".
111
+ * `instance_package_timeout` - The number of seconds to wait for the instance
112
+ to be burnt into an AMI during packaging. Defaults to 600 seconds.
113
+ * `instance_type` - The type of instance, such as "m3.medium". The default
114
+ value of this if not specified is "m3.medium". "m1.small" has been
115
+ deprecated in "us-east-1" and "m3.medium" is the smallest instance
116
+ type to support both paravirtualization and hvm AMIs
110
117
  * `keypair_name` - The name of the keypair to use to bootstrap AMIs
111
118
  which support it.
119
+ * `session_token` - The session token provided by STS
112
120
  * `private_ip_address` - The private IP address to assign to an instance
113
121
  within a [VPC](http://aws.amazon.com/vpc/)
122
+ * `elastic_ip` - Can be set to 'true', or to an existing Elastic IP address.
123
+ If true, allocate a new Elastic IP address to the instance. If set
124
+ to an existing Elastic IP address, assign the address to the instance.
114
125
  * `region` - The region to start the instance in, such as "us-east-1"
115
126
  * `secret_access_key` - The secret access key for accessing AWS
116
127
  * `security_groups` - An array of security groups for the instance. If this
117
128
  instance will be launched in VPC, this must be a list of security group
118
- Name.
129
+ Name. For a nondefault VPC, you must use security group IDs instead (http://docs.aws.amazon.com/cli/latest/reference/ec2/run-instances.html).
119
130
  * `iam_instance_profile_arn` - The Amazon resource name (ARN) of the IAM Instance
120
131
  Profile to associate with the instance
121
132
  * `iam_instance_profile_name` - The name of the IAM Instance Profile to associate
@@ -184,8 +195,8 @@ There is minimal support for synced folders. Upon `vagrant up`,
184
195
  `rsync` (if available) to uni-directionally sync the folder to
185
196
  the remote machine over SSH.
186
197
 
187
- This is good enough for all built-in Vagrant provisioners (shell,
188
- chef, and puppet) to work!
198
+ See [Vagrant Synced folders: rsync](https://docs.vagrantup.com/v2/synced-folders/rsync.html)
199
+
189
200
 
190
201
  ## Other Examples
191
202
 
@@ -8,6 +8,21 @@ module VagrantPlugins
8
8
  # Include the built-in modules so we can use them as top-level things.
9
9
  include Vagrant::Action::Builtin
10
10
 
11
+ def self.action_package
12
+ Vagrant::Action::Builder.new.tap do |b|
13
+ b.use Call, IsCreated do |env, b2|
14
+ if !env[:result]
15
+ b2.use MessageNotCreated
16
+ next
17
+ end
18
+
19
+ # Connect to AWS and then Create a package from the server instance
20
+ b2.use ConnectAWS
21
+ b2.use PackageInstance
22
+ end
23
+ end
24
+ end
25
+
11
26
  # This action is called to halt the remote machine.
12
27
  def self.action_halt
13
28
  Vagrant::Action::Builder.new.tap do |b|
@@ -30,16 +45,16 @@ module VagrantPlugins
30
45
  b.use Call, DestroyConfirm do |env, b2|
31
46
  if env[:result]
32
47
  b2.use ConfigValidate
33
- b.use Call, IsCreated do |env2, b3|
48
+ b2.use Call, IsCreated do |env2, b3|
34
49
  if !env2[:result]
35
50
  b3.use MessageNotCreated
36
51
  next
37
52
  end
53
+ b3.use ConnectAWS
54
+ b3.use ElbDeregisterInstance
55
+ b3.use TerminateInstance
56
+ b3.use ProvisionerCleanup if defined?(ProvisionerCleanup)
38
57
  end
39
- b2.use ConnectAWS
40
- b2.use ElbDeregisterInstance
41
- b2.use TerminateInstance
42
- b2.use ProvisionerCleanup if defined?(ProvisionerCleanup)
43
58
  else
44
59
  b2.use MessageWillNotDestroy
45
60
  end
@@ -58,7 +73,7 @@ module VagrantPlugins
58
73
  end
59
74
 
60
75
  b2.use Provision
61
- b2.use SyncFolders
76
+ b2.use SyncedFolders
62
77
  end
63
78
  end
64
79
  end
@@ -117,7 +132,7 @@ module VagrantPlugins
117
132
  def self.action_prepare_boot
118
133
  Vagrant::Action::Builder.new.tap do |b|
119
134
  b.use Provision
120
- b.use SyncFolders
135
+ b.use SyncedFolders
121
136
  b.use WarnNetworks
122
137
  b.use ElbRegisterInstance
123
138
  end
@@ -126,7 +141,7 @@ module VagrantPlugins
126
141
  # This action is called to bring the box up from nothing.
127
142
  def self.action_up
128
143
  Vagrant::Action::Builder.new.tap do |b|
129
- b.use HandleBoxUrl
144
+ b.use HandleBox
130
145
  b.use ConfigValidate
131
146
  b.use ConnectAWS
132
147
  b.use Call, IsCreated do |env1, b1|
@@ -177,12 +192,12 @@ module VagrantPlugins
177
192
  autoload :MessageAlreadyCreated, action_root.join("message_already_created")
178
193
  autoload :MessageNotCreated, action_root.join("message_not_created")
179
194
  autoload :MessageWillNotDestroy, action_root.join("message_will_not_destroy")
195
+ autoload :PackageInstance, action_root.join("package_instance")
180
196
  autoload :ReadSSHInfo, action_root.join("read_ssh_info")
181
197
  autoload :ReadState, action_root.join("read_state")
182
198
  autoload :RunInstance, action_root.join("run_instance")
183
199
  autoload :StartInstance, action_root.join("start_instance")
184
200
  autoload :StopInstance, action_root.join("stop_instance")
185
- autoload :SyncFolders, action_root.join("sync_folders")
186
201
  autoload :TerminateInstance, action_root.join("terminate_instance")
187
202
  autoload :TimedProvision, action_root.join("timed_provision") # some plugins now expect this action to exist
188
203
  autoload :WaitForState, action_root.join("wait_for_state")
@@ -30,6 +30,7 @@ module VagrantPlugins
30
30
  else
31
31
  fog_config[:aws_access_key_id] = region_config.access_key_id
32
32
  fog_config[:aws_secret_access_key] = region_config.secret_access_key
33
+ fog_config[:aws_session_token] = region_config.session_token
33
34
  end
34
35
 
35
36
  fog_config[:endpoint] = region_config.endpoint if region_config.endpoint
@@ -37,7 +38,7 @@ module VagrantPlugins
37
38
 
38
39
  @logger.info("Connecting to AWS...")
39
40
  env[:aws_compute] = Fog::Compute.new(fog_config)
40
- env[:aws_elb] = Fog::AWS::ELB.new(fog_config.except(:provider))
41
+ env[:aws_elb] = Fog::AWS::ELB.new(fog_config.except(:provider, :endpoint))
41
42
 
42
43
  @app.call(env)
43
44
  end
@@ -0,0 +1,192 @@
1
+ require "log4r"
2
+ require 'vagrant/util/template_renderer'
3
+ require 'vagrant-aws/util/timer'
4
+ require 'vagrant/action/general/package'
5
+
6
+ module VagrantPlugins
7
+ module AWS
8
+ module Action
9
+ # This action packages a running aws-based server into an
10
+ # aws-based vagrant box. It does so by burning the associated
11
+ # vagrant-aws server instance, into an AMI via fog. Upon
12
+ # successful AMI burning, the action will create a .box tarball
13
+ # writing a Vagrantfile with the fresh AMI id into it.
14
+
15
+ # Vagrant itself comes with a general package action, which
16
+ # this plugin action does call. The general action provides
17
+ # the actual packaging as well as other options such as
18
+ # --include for including additional files and --vagrantfile
19
+ # which is pretty much not useful here anyway.
20
+
21
+ # The virtualbox package plugin action was loosely used
22
+ # as a model for this class.
23
+
24
+ class PackageInstance < Vagrant::Action::General::Package
25
+ include Vagrant::Util::Retryable
26
+
27
+ def initialize(app, env)
28
+ @app = app
29
+ @logger = Log4r::Logger.new("vagrant_aws::action::package_instance")
30
+ env["package.include"] ||= []
31
+ env["package.output"] ||= "package.box"
32
+ end
33
+
34
+ alias_method :general_call, :call
35
+ def call(env)
36
+ # Initialize metrics if they haven't been
37
+ env[:metrics] ||= {}
38
+
39
+ # This block attempts to burn the server instance into an AMI
40
+ begin
41
+ # Get the Fog server object for given machine
42
+ server = env[:aws_compute].servers.get(env[:machine].id)
43
+
44
+ env[:ui].info(I18n.t("vagrant_aws.packaging_instance", :instance_id => server.id))
45
+
46
+ # Make the request to AWS to create an AMI from machine's instance
47
+ ami_response = server.service.create_image server.id, "#{server.tags["Name"]} Package - #{Time.now.strftime("%Y%m%d-%H%M%S")}", ""
48
+
49
+ # Find ami id
50
+ @ami_id = ami_response.data[:body]["imageId"]
51
+
52
+ # Attempt to burn the aws instance into an AMI within timeout
53
+ env[:metrics]["instance_ready_time"] = Util::Timer.time do
54
+
55
+ # Get the config, to set the ami burn timeout
56
+ region = env[:machine].provider_config.region
57
+ region_config = env[:machine].provider_config.get_region_config(region)
58
+ tries = region_config.instance_package_timeout / 2
59
+
60
+ env[:ui].info(I18n.t("vagrant_aws.burning_ami", :ami_id => @ami_id))
61
+
62
+ # Check the status of the AMI every 2 seconds until the ami burn timeout has been reached
63
+ begin
64
+ retryable(:on => Fog::Errors::TimeoutError, :tries => tries) do
65
+ # If we're interrupted don't worry about waiting
66
+ next if env[:interrupted]
67
+
68
+ # Need to update the ami_obj on each cycle
69
+ ami_obj = server.service.images.get(@ami_id)
70
+
71
+ # Wait for the server to be ready, raise error if timeout reached
72
+ server.wait_for(2) {
73
+ if ami_obj.state == "failed"
74
+ raise Errors::InstancePackageError,
75
+ ami_id: ami_obj.id,
76
+ err: ami_obj.state
77
+ return
78
+ else
79
+ # Successful AMI burn will result in true here
80
+ ami_obj.ready?
81
+ end
82
+ }
83
+ end
84
+ rescue Fog::Errors::TimeoutError
85
+ # Notify the user upon timeout
86
+ raise Errors::InstancePackageTimeout,
87
+ timeout: region_config.instance_package_timeout
88
+ end
89
+ end
90
+ env[:ui].info(I18n.t("vagrant_aws.packaging_instance_complete", :time_seconds => env[:metrics]["instance_ready_time"].to_i))
91
+ rescue Fog::Compute::AWS::Error => e
92
+ raise Errors::FogError, :message => e.message
93
+ end
94
+
95
+ # Handles inclusions from --include and --vagrantfile options
96
+ setup_package_files(env)
97
+
98
+ # Setup the temporary directory for the tarball files
99
+ @temp_dir = env[:tmp_path].join(Time.now.to_i.to_s)
100
+ env["export.temp_dir"] = @temp_dir
101
+ FileUtils.mkpath(env["export.temp_dir"])
102
+
103
+ # Create the Vagrantfile and metadata.json files from templates to go in the box
104
+ create_vagrantfile(env)
105
+ create_metadata_file(env)
106
+
107
+ # Just match up a couple environmental variables so that
108
+ # the superclass will do the right thing. Then, call the
109
+ # superclass to actually create the tarball (.box file)
110
+ env["package.directory"] = env["export.temp_dir"]
111
+ general_call(env)
112
+
113
+ # Always call recover to clean up the temp dir
114
+ clean_temp_dir
115
+ end
116
+
117
+ protected
118
+
119
+ # Cleanup temp dir and files
120
+ def clean_temp_dir
121
+ if @temp_dir && File.exist?(@temp_dir)
122
+ FileUtils.rm_rf(@temp_dir)
123
+ end
124
+ end
125
+
126
+ # This method generates the Vagrantfile at the root of the box. Taken from
127
+ # VagrantPlugins::ProviderVirtualBox::Action::PackageVagrantfile
128
+ def create_vagrantfile env
129
+ File.open(File.join(env["export.temp_dir"], "Vagrantfile"), "w") do |f|
130
+ f.write(TemplateRenderer.render("vagrant-aws_package_Vagrantfile", {
131
+ region: env[:machine].provider_config.region,
132
+ ami: @ami_id,
133
+ template_root: template_root
134
+ }))
135
+ end
136
+ end
137
+
138
+ # This method generates the metadata.json file at the root of the box.
139
+ def create_metadata_file env
140
+ File.open(File.join(env["export.temp_dir"], "metadata.json"), "w") do |f|
141
+ f.write(TemplateRenderer.render("metadata.json", {
142
+ template_root: template_root
143
+ }))
144
+ end
145
+ end
146
+
147
+ # Sets up --include and --vagrantfile files which may be added as optional
148
+ # parameters. Taken from VagrantPlugins::ProviderVirtualBox::Action::SetupPackageFiles
149
+ def setup_package_files(env)
150
+ files = {}
151
+ env["package.include"].each do |file|
152
+ source = Pathname.new(file)
153
+ dest = nil
154
+
155
+ # If the source is relative then we add the file as-is to the include
156
+ # directory. Otherwise, we copy only the file into the root of the
157
+ # include directory. Kind of strange, but seems to match what people
158
+ # expect based on history.
159
+ if source.relative?
160
+ dest = source
161
+ else
162
+ dest = source.basename
163
+ end
164
+
165
+ # Assign the mapping
166
+ files[file] = dest
167
+ end
168
+
169
+ if env["package.vagrantfile"]
170
+ # Vagrantfiles are treated special and mapped to a specific file
171
+ files[env["package.vagrantfile"]] = "_Vagrantfile"
172
+ end
173
+
174
+ # Verify the mapping
175
+ files.each do |from, _|
176
+ raise Vagrant::Errors::PackageIncludeMissing,
177
+ file: from if !File.exist?(from)
178
+ end
179
+
180
+ # Save the mapping
181
+ env["package.files"] = files
182
+ end
183
+
184
+ # Used to find the base location of aws-vagrant templates
185
+ def template_root
186
+ AWS.source_root.join("templates")
187
+ end
188
+
189
+ end
190
+ end
191
+ end
192
+ end
@@ -95,11 +95,10 @@ module VagrantPlugins
95
95
  if !security_groups.empty?
96
96
  security_group_key = options[:subnet_id].nil? ? :groups : :security_group_ids
97
97
  options[security_group_key] = security_groups
98
+ env[:ui].warn(I18n.t("vagrant_aws.warn_ssh_access")) unless allows_ssh_port?(env, security_groups, subnet_id)
98
99
  end
99
100
 
100
101
  begin
101
- env[:ui].warn(I18n.t("vagrant_aws.warn_ssh_access")) unless allows_ssh_port?(env, security_groups, subnet_id)
102
-
103
102
  server = env[:aws_compute].servers.create(options)
104
103
  rescue Fog::Compute::AWS::NotFound => e
105
104
  # Invalid subnet doesn't have its own error so we catch and
@@ -132,7 +131,7 @@ module VagrantPlugins
132
131
  next if env[:interrupted]
133
132
 
134
133
  # Wait for the server to be ready
135
- server.wait_for(2) { ready? }
134
+ server.wait_for(2, 5) { ready? }
136
135
  end
137
136
  rescue Fog::Errors::TimeoutError
138
137
  # Delete the instance
@@ -149,7 +148,7 @@ module VagrantPlugins
149
148
  # Allocate and associate an elastic IP if requested
150
149
  if elastic_ip
151
150
  domain = subnet_id ? 'vpc' : 'standard'
152
- do_elastic_ip(env, domain, server)
151
+ do_elastic_ip(env, domain, server, elastic_ip)
153
152
  end
154
153
 
155
154
  if !env[:interrupted]
@@ -198,26 +197,45 @@ module VagrantPlugins
198
197
  !rules.select { |r| (r["fromPort"]..r["toPort"]).include?(port) }.empty?
199
198
  end
200
199
 
201
- def do_elastic_ip(env, domain, server)
202
- begin
203
- allocation = env[:aws_compute].allocate_address(domain)
204
- rescue
205
- @logger.debug("Could not allocate Elastic IP.")
206
- terminate(env)
207
- raise Errors::FogError,
208
- :message => "Could not allocate Elastic IP."
200
+ def do_elastic_ip(env, domain, server, elastic_ip)
201
+ if elastic_ip =~ /\d+\.\d+\.\d+\.\d+/
202
+ begin
203
+ address = env[:aws_compute].addresses.get(elastic_ip)
204
+ rescue
205
+ handle_elastic_ip_error(env, "Could not retrieve Elastic IP: #{elastic_ip}")
206
+ end
207
+ if address.nil?
208
+ handle_elastic_ip_error(env, "Elastic IP not available: #{elastic_ip}")
209
+ end
210
+ @logger.debug("Public IP #{address.public_ip}")
211
+ else
212
+ begin
213
+ allocation = env[:aws_compute].allocate_address(domain)
214
+ rescue
215
+ handle_elastic_ip_error(env, "Could not allocate Elastic IP.")
216
+ end
217
+ @logger.debug("Public IP #{allocation.body['publicIp']}")
209
218
  end
210
- @logger.debug("Public IP #{allocation.body['publicIp']}")
211
219
 
212
220
  # Associate the address and save the metadata to a hash
221
+ h = nil
213
222
  if domain == 'vpc'
214
223
  # VPC requires an allocation ID to assign an IP
215
- association = env[:aws_compute].associate_address(server.id, nil, nil, allocation.body['allocationId'])
216
- h = { :allocation_id => allocation.body['allocationId'], :association_id => association.body['associationId'], :public_ip => allocation.body['publicIp'] }
224
+ if address
225
+ association = env[:aws_compute].associate_address(server.id, nil, nil, address.allocation_id)
226
+ else
227
+ association = env[:aws_compute].associate_address(server.id, nil, nil, allocation.body['allocationId'])
228
+ # Only store release data for an allocated address
229
+ h = { :allocation_id => allocation.body['allocationId'], :association_id => association.body['associationId'], :public_ip => allocation.body['publicIp'] }
230
+ end
217
231
  else
218
232
  # Standard EC2 instances only need the allocated IP address
219
- association = env[:aws_compute].associate_address(server.id, allocation.body['publicIp'])
220
- h = { :public_ip => allocation.body['publicIp'] }
233
+ if address
234
+ association = env[:aws_compute].associate_address(server.id, address.public_ip)
235
+ else
236
+ association = env[:aws_compute].associate_address(server.id, allocation.body['publicIp'])
237
+ h = { :public_ip => allocation.body['publicIp'] }
238
+ end
221
239
  end
222
240
 
223
241
  unless association.body['return']
@@ -228,12 +246,21 @@ module VagrantPlugins
228
246
  end
229
247
 
230
248
  # Save this IP to the data dir so it can be released when the instance is destroyed
231
- ip_file = env[:machine].data_dir.join('elastic_ip')
232
- ip_file.open('w+') do |f|
233
- f.write(h.to_json)
249
+ if h
250
+ ip_file = env[:machine].data_dir.join('elastic_ip')
251
+ ip_file.open('w+') do |f|
252
+ f.write(h.to_json)
253
+ end
234
254
  end
235
255
  end
236
256
 
257
+ def handle_elastic_ip_error(env, message)
258
+ @logger.debug(message)
259
+ terminate(env)
260
+ raise Errors::FogError,
261
+ :message => message
262
+ end
263
+
237
264
  def terminate(env)
238
265
  destroy_env = env.dup
239
266
  destroy_env.delete(:interrupted)
@@ -12,7 +12,11 @@ module VagrantPlugins
12
12
  end
13
13
 
14
14
  def call(env)
15
- server = env[:aws_compute].servers.get(env[:machine].id)
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
16
20
 
17
21
  # Release the elastic IP
18
22
  ip_file = env[:machine].data_dir.join('elastic_ip')
@@ -24,7 +24,12 @@ module VagrantPlugins
24
24
  # @return [Fixnum]
25
25
  attr_accessor :instance_ready_timeout
26
26
 
27
- # The type of instance to launch, such as "m1.small"
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"
28
33
  #
29
34
  # @return [String]
30
35
  attr_accessor :instance_type
@@ -39,9 +44,10 @@ module VagrantPlugins
39
44
  # @return [String]
40
45
  attr_accessor :private_ip_address
41
46
 
42
- # Acquire and attach an elastic IP address (VPC).
47
+ # If true, acquire and attach an elastic IP address.
48
+ # If set to an IP address, assign to the instance.
43
49
  #
44
- # @return [Boolean]
50
+ # @return [String]
45
51
  attr_accessor :elastic_ip
46
52
 
47
53
  # The name of the AWS region in which to create the instance.
@@ -64,6 +70,11 @@ module VagrantPlugins
64
70
  # @return [String]
65
71
  attr_accessor :secret_access_key
66
72
 
73
+ # The token associated with the key for accessing AWS.
74
+ #
75
+ # @return [String]
76
+ attr_accessor :session_token
77
+
67
78
  # The security groups to set on the instance. For VPC this must
68
79
  # be a list of IDs. For EC2, it can be either.
69
80
  #
@@ -145,32 +156,34 @@ module VagrantPlugins
145
156
  attr_accessor :elb
146
157
 
147
158
  def initialize(region_specific=false)
148
- @access_key_id = UNSET_VALUE
149
- @ami = UNSET_VALUE
150
- @availability_zone = UNSET_VALUE
151
- @instance_ready_timeout = UNSET_VALUE
152
- @instance_type = UNSET_VALUE
153
- @keypair_name = UNSET_VALUE
154
- @private_ip_address = UNSET_VALUE
155
- @region = UNSET_VALUE
156
- @endpoint = UNSET_VALUE
157
- @version = UNSET_VALUE
158
- @secret_access_key = UNSET_VALUE
159
- @security_groups = UNSET_VALUE
160
- @subnet_id = UNSET_VALUE
161
- @tags = {}
162
- @user_data = UNSET_VALUE
163
- @use_iam_profile = UNSET_VALUE
164
- @block_device_mapping = []
165
- @elastic_ip = UNSET_VALUE
159
+ @access_key_id = UNSET_VALUE
160
+ @ami = UNSET_VALUE
161
+ @availability_zone = UNSET_VALUE
162
+ @instance_ready_timeout = UNSET_VALUE
163
+ @instance_package_timeout = UNSET_VALUE
164
+ @instance_type = UNSET_VALUE
165
+ @keypair_name = UNSET_VALUE
166
+ @private_ip_address = UNSET_VALUE
167
+ @region = UNSET_VALUE
168
+ @endpoint = UNSET_VALUE
169
+ @version = UNSET_VALUE
170
+ @secret_access_key = UNSET_VALUE
171
+ @session_token = UNSET_VALUE
172
+ @security_groups = UNSET_VALUE
173
+ @subnet_id = UNSET_VALUE
174
+ @tags = {}
175
+ @user_data = UNSET_VALUE
176
+ @use_iam_profile = UNSET_VALUE
177
+ @block_device_mapping = []
178
+ @elastic_ip = UNSET_VALUE
166
179
  @iam_instance_profile_arn = UNSET_VALUE
167
180
  @iam_instance_profile_name = UNSET_VALUE
168
- @terminate_on_shutdown = UNSET_VALUE
169
- @ssh_host_attribute = UNSET_VALUE
170
- @monitoring = UNSET_VALUE
171
- @ebs_optimized = UNSET_VALUE
172
- @associate_public_ip = UNSET_VALUE
173
- @elb = UNSET_VALUE
181
+ @terminate_on_shutdown = UNSET_VALUE
182
+ @ssh_host_attribute = UNSET_VALUE
183
+ @monitoring = UNSET_VALUE
184
+ @ebs_optimized = UNSET_VALUE
185
+ @associate_public_ip = UNSET_VALUE
186
+ @elb = UNSET_VALUE
174
187
 
175
188
  # Internal state (prefix with __ so they aren't automatically
176
189
  # merged)
@@ -255,6 +268,7 @@ module VagrantPlugins
255
268
  # will default to nil if the environment variables are not present.
256
269
  @access_key_id = ENV['AWS_ACCESS_KEY'] if @access_key_id == UNSET_VALUE
257
270
  @secret_access_key = ENV['AWS_SECRET_KEY'] if @secret_access_key == UNSET_VALUE
271
+ @session_token = ENV['AWS_SESSION_TOKEN'] if @session_token == UNSET_VALUE
258
272
 
259
273
  # AMI must be nil, since we can't default that
260
274
  @ami = nil if @ami == UNSET_VALUE
@@ -262,8 +276,11 @@ module VagrantPlugins
262
276
  # Set the default timeout for waiting for an instance to be ready
263
277
  @instance_ready_timeout = 120 if @instance_ready_timeout == UNSET_VALUE
264
278
 
265
- # Default instance type is an m1.small
266
- @instance_type = "m1.small" if @instance_type == UNSET_VALUE
279
+ # Set the default timeout for waiting for an instance to burn into and ami
280
+ @instance_package_timeout = 600 if @instance_package_timeout == UNSET_VALUE
281
+
282
+ # Default instance type is an m3.medium
283
+ @instance_type = "m3.medium" if @instance_type == UNSET_VALUE
267
284
 
268
285
  # Keypair defaults to nil
269
286
  @keypair_name = nil if @keypair_name == UNSET_VALUE
@@ -19,6 +19,14 @@ module VagrantPlugins
19
19
  error_key(:instance_ready_timeout)
20
20
  end
21
21
 
22
+ class InstancePackageError < VagrantAWSError
23
+ error_key(:instance_package_error)
24
+ end
25
+
26
+ class InstancePackageTimeout < VagrantAWSError
27
+ error_key(:instance_package_timeout)
28
+ end
29
+
22
30
  class RsyncError < VagrantAWSError
23
31
  error_key(:rsync_error)
24
32
  end
@@ -1,5 +1,5 @@
1
1
  module VagrantPlugins
2
2
  module AWS
3
- VERSION = "0.5.0"
3
+ VERSION = '0.6.0'
4
4
  end
5
5
  end
@@ -2,6 +2,8 @@ en:
2
2
  vagrant_aws:
3
3
  already_status: |-
4
4
  The machine is already %{status}.
5
+ burning_ami: |-
6
+ Waiting for the AMI '%{ami_id}' to burn...
5
7
  elb:
6
8
  adjusting: |-
7
9
  Adjusting availability zones of ELB %{elb_name}...
@@ -26,6 +28,10 @@ en:
26
28
  to SSH into it.
27
29
  not_created: |-
28
30
  Instance is not created. Please run `vagrant up` first.
31
+ packaging_instance: |-
32
+ Burning instance %{instance_id} into an ami
33
+ packaging_instance_complete: |-
34
+ Burn was successful in %{time_seconds}s
29
35
  ready: |-
30
36
  Machine is booted and ready for use!
31
37
  rsync_not_found_warning: |-
@@ -85,6 +91,17 @@ en:
85
91
  set waiting for the instance to become ready is %{timeout} seconds.
86
92
  Please verify that the machine properly boots. If you need more time
87
93
  set the `instance_ready_timeout` configuration on the AWS provider.
94
+ instance_package_error: |-
95
+ There was an error packaging the instance. See details below for more info.
96
+
97
+ AMI Id: %{ami_id}
98
+ Error: %{err}
99
+ instance_package_timeout: |-
100
+ The AMI failed to become "ready" in AWS. The timeout currently
101
+ set waiting for the instance to become ready is %{timeout} seconds. For
102
+ larger instances AMI burning may take long periods of time. Please
103
+ ensure the timeout is set high enough, it can be changed by adjusting
104
+ the `instance_package_timeout` configuration on the AWS provider.
88
105
  rsync_error: |-
89
106
  There was an error when attempting to rsync a shared folder.
90
107
  Please inspect the error message below for more info.
@@ -19,11 +19,13 @@ describe VagrantPlugins::AWS::Config do
19
19
  its("ami") { should be_nil }
20
20
  its("availability_zone") { should be_nil }
21
21
  its("instance_ready_timeout") { should == 120 }
22
- its("instance_type") { should == "m1.small" }
22
+ its("instance_package_timeout") { should == 600 }
23
+ its("instance_type") { should == "m3.medium" }
23
24
  its("keypair_name") { should be_nil }
24
25
  its("private_ip_address") { should be_nil }
25
26
  its("region") { should == "us-east-1" }
26
27
  its("secret_access_key") { should be_nil }
28
+ its("session_token") { should be_nil }
27
29
  its("security_groups") { should == [] }
28
30
  its("subnet_id") { should be_nil }
29
31
  its("iam_instance_profile_arn") { should be_nil }
@@ -46,9 +48,9 @@ describe VagrantPlugins::AWS::Config do
46
48
  # each of these attributes to "foo" in isolation, and reads the value
47
49
  # and asserts the proper result comes back out.
48
50
  [:access_key_id, :ami, :availability_zone, :instance_ready_timeout,
49
- :instance_type, :keypair_name, :ssh_host_attribute, :ebs_optimized,
50
- :region, :secret_access_key, :monitoring, :associate_public_ip,
51
- :subnet_id, :tags, :elastic_ip, :terminate_on_shutdown,
51
+ :instance_package_timeout, :instance_type, :keypair_name, :ssh_host_attribute,
52
+ :ebs_optimized, :region, :secret_access_key, :session_token, :monitoring,
53
+ :associate_public_ip, :subnet_id, :tags, :elastic_ip, :terminate_on_shutdown,
52
54
  :iam_instance_profile_arn, :iam_instance_profile_name,
53
55
  :use_iam_profile, :user_data, :block_device_mapping].each do |attribute|
54
56
 
@@ -75,12 +77,14 @@ describe VagrantPlugins::AWS::Config do
75
77
 
76
78
  its("access_key_id") { should be_nil }
77
79
  its("secret_access_key") { should be_nil }
80
+ its("session_token") { should be_nil }
78
81
  end
79
82
 
80
83
  context "with EC2 credential environment variables" do
81
84
  before :each do
82
85
  ENV.stub(:[]).with("AWS_ACCESS_KEY").and_return("access_key")
83
86
  ENV.stub(:[]).with("AWS_SECRET_KEY").and_return("secret_key")
87
+ ENV.stub(:[]).with("AWS_SESSION_TOKEN").and_return("session_token")
84
88
  end
85
89
 
86
90
  subject do
@@ -91,6 +95,7 @@ describe VagrantPlugins::AWS::Config do
91
95
 
92
96
  its("access_key_id") { should == "access_key" }
93
97
  its("secret_access_key") { should == "secret_key" }
98
+ its("session_token") { should == "session_token" }
94
99
  end
95
100
  end
96
101
 
@@ -101,6 +106,7 @@ describe VagrantPlugins::AWS::Config do
101
106
  let(:config_keypair_name) { "foo" }
102
107
  let(:config_region) { "foo" }
103
108
  let(:config_secret_access_key) { "foo" }
109
+ let(:config_session_token) { "foo" }
104
110
 
105
111
  def set_test_values(instance)
106
112
  instance.access_key_id = config_access_key_id
@@ -109,6 +115,7 @@ describe VagrantPlugins::AWS::Config do
109
115
  instance.keypair_name = config_keypair_name
110
116
  instance.region = config_region
111
117
  instance.secret_access_key = config_secret_access_key
118
+ instance.session_token = config_session_token
112
119
  end
113
120
 
114
121
  it "should raise an exception if not finalized" do
@@ -134,6 +141,7 @@ describe VagrantPlugins::AWS::Config do
134
141
  its("keypair_name") { should == config_keypair_name }
135
142
  its("region") { should == config_region }
136
143
  its("secret_access_key") { should == config_secret_access_key }
144
+ its("session_token") { should == config_session_token }
137
145
  end
138
146
 
139
147
  context "with a specific config set" do
@@ -158,6 +166,7 @@ describe VagrantPlugins::AWS::Config do
158
166
  its("keypair_name") { should == config_keypair_name }
159
167
  its("region") { should == region_name }
160
168
  its("secret_access_key") { should == config_secret_access_key }
169
+ its("session_token") { should == config_session_token }
161
170
  end
162
171
 
163
172
  describe "inheritance of parent config" do
@@ -0,0 +1,3 @@
1
+ {
2
+ "provider": "aws"
3
+ }
@@ -0,0 +1,5 @@
1
+ Vagrant.configure("2") do |config|
2
+ config.vm.provider "aws" do |aws|
3
+ aws.region_config "<%= region %>", ami: "<%= ami %>"
4
+ end
5
+ end
@@ -18,9 +18,8 @@ Gem::Specification.new do |s|
18
18
  s.add_runtime_dependency "fog", "~> 1.22"
19
19
 
20
20
  s.add_development_dependency "rake"
21
- s.add_development_dependency "rspec-core", "~> 2.12.2"
22
- s.add_development_dependency "rspec-expectations", "~> 2.12.1"
23
- s.add_development_dependency "rspec-mocks", "~> 2.12.1"
21
+ s.add_development_dependency "rspec", "~> 2.12"
22
+ s.add_development_dependency "rspec-its"
24
23
 
25
24
  # The following block of code determines the files that should be included
26
25
  # in the gem. It does this by reading all the files in the directory where
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.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mitchell Hashimoto
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-06-22 00:00:00.000000000 Z
11
+ date: 2014-12-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fog
@@ -39,47 +39,33 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: rspec-core
42
+ name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 2.12.2
47
+ version: '2.12'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 2.12.2
54
+ version: '2.12'
55
55
  - !ruby/object:Gem::Dependency
56
- name: rspec-expectations
56
+ name: rspec-its
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: 2.12.1
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: 2.12.1
69
- - !ruby/object:Gem::Dependency
70
- name: rspec-mocks
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - "~>"
59
+ - - ">="
74
60
  - !ruby/object:Gem::Version
75
- version: 2.12.1
61
+ version: '0'
76
62
  type: :development
77
63
  prerelease: false
78
64
  version_requirements: !ruby/object:Gem::Requirement
79
65
  requirements:
80
- - - "~>"
66
+ - - ">="
81
67
  - !ruby/object:Gem::Version
82
- version: 2.12.1
68
+ version: '0'
83
69
  description: Enables Vagrant to manage machines in EC2 and VPC.
84
70
  email: mitchell@hashicorp.com
85
71
  executables: []
@@ -98,7 +84,6 @@ files:
98
84
  - example_box/metadata.json
99
85
  - lib/vagrant-aws.rb
100
86
  - lib/vagrant-aws/action.rb
101
- - lib/vagrant-aws/action/.sync_folders.rb.swp
102
87
  - lib/vagrant-aws/action/connect_aws.rb
103
88
  - lib/vagrant-aws/action/elb_deregister_instance.rb
104
89
  - lib/vagrant-aws/action/elb_register_instance.rb
@@ -107,12 +92,12 @@ files:
107
92
  - lib/vagrant-aws/action/message_already_created.rb
108
93
  - lib/vagrant-aws/action/message_not_created.rb
109
94
  - lib/vagrant-aws/action/message_will_not_destroy.rb
95
+ - lib/vagrant-aws/action/package_instance.rb
110
96
  - lib/vagrant-aws/action/read_ssh_info.rb
111
97
  - lib/vagrant-aws/action/read_state.rb
112
98
  - lib/vagrant-aws/action/run_instance.rb
113
99
  - lib/vagrant-aws/action/start_instance.rb
114
100
  - lib/vagrant-aws/action/stop_instance.rb
115
- - lib/vagrant-aws/action/sync_folders.rb
116
101
  - lib/vagrant-aws/action/terminate_instance.rb
117
102
  - lib/vagrant-aws/action/timed_provision.rb
118
103
  - lib/vagrant-aws/action/wait_for_state.rb
@@ -126,9 +111,9 @@ files:
126
111
  - lib/vagrant-aws/version.rb
127
112
  - locales/en.yml
128
113
  - spec/spec_helper.rb
129
- - spec/vagrant-aws/actions/.syncfolders_spec.rb.swp
130
- - spec/vagrant-aws/actions/syncfolders_spec.rb
131
114
  - spec/vagrant-aws/config_spec.rb
115
+ - templates/metadata.json.erb
116
+ - templates/vagrant-aws_package_Vagrantfile.erb
132
117
  - vagrant-aws.gemspec
133
118
  homepage: http://www.vagrantup.com
134
119
  licenses:
@@ -150,7 +135,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
150
135
  version: 1.3.6
151
136
  requirements: []
152
137
  rubyforge_project: vagrant-aws
153
- rubygems_version: 2.2.2
138
+ rubygems_version: 2.4.5
154
139
  signing_key:
155
140
  specification_version: 4
156
141
  summary: Enables Vagrant to manage machines in EC2 and VPC.
@@ -1,130 +0,0 @@
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", "--delete",
87
- *excludes.map{|e|['--exclude', e]}.flatten,
88
- "-e", "ssh -p #{ssh_info[:port]} #{ssh_key_options(ssh_info)} " +
89
- ssh_options_to_args(ssh_options).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
- # Generate a ssh(1) command line list of options
110
- #
111
- # @param [Array] options An array of ssh options. E.g.
112
- # `StrictHostKeyChecking=no` see ssh_config(5) for more
113
- # @return [Array] Computed list of command line arguments
114
- def ssh_options_to_args(options)
115
- # Bail early if we get something that is not an array of options
116
- return [] unless options
117
-
118
- return options.map { |o| "-o '#{o}'" }
119
- end
120
-
121
- private
122
-
123
- def ssh_key_options(ssh_info)
124
- # Ensure that `private_key_path` is an Array (for Vagrant < 1.4)
125
- Array(ssh_info[:private_key_path]).map { |path| "-i '#{path}' " }.join
126
- end
127
- end
128
- end
129
- end
130
- end
@@ -1,28 +0,0 @@
1
- require 'spec_helper'
2
- require 'vagrant-aws/action/sync_folders'
3
-
4
- describe VagrantPlugins::AWS::Action::SyncFolders do
5
- let(:app) { nil }
6
- let(:env) { {} }
7
- subject(:action) { described_class.new(app, env) }
8
-
9
- describe '#ssh_options_to_args' do
10
- subject(:args) { action.ssh_options_to_args(options) }
11
-
12
- context 'with no ssh options' do
13
- let(:options) { [] }
14
-
15
- it { should eql [] }
16
- end
17
-
18
- context 'with one option' do
19
- let(:options) { ['StrictHostKeyChecking=no'] }
20
- it { should eql ["-o 'StrictHostKeyChecking=no'"] }
21
- end
22
-
23
- context 'with multiple options' do
24
- let(:options) { ['SHKC=no', 'Port=222'] }
25
- it { should eql ["-o 'SHKC=no'", "-o 'Port=222'"] }
26
- end
27
- end
28
- end