vagrant-aws 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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