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