vagrant-mcs 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 +7 -0
- data/.gitignore +21 -0
- data/.rspec +1 -0
- data/CHANGELOG.md +92 -0
- data/Gemfile +12 -0
- data/LICENSE +8 -0
- data/README.md +292 -0
- data/Rakefile +21 -0
- data/dummy.box +0 -0
- data/example_box/README.md +13 -0
- data/example_box/mcs.box +0 -0
- data/example_box/metadata.json +3 -0
- data/lib/vagrant-mcs/action/connect_mcs.rb +51 -0
- data/lib/vagrant-mcs/action/elb_deregister_instance.rb +24 -0
- data/lib/vagrant-mcs/action/elb_register_instance.rb +24 -0
- data/lib/vagrant-mcs/action/is_created.rb +18 -0
- data/lib/vagrant-mcs/action/is_stopped.rb +18 -0
- data/lib/vagrant-mcs/action/message_already_created.rb +16 -0
- data/lib/vagrant-mcs/action/message_not_created.rb +16 -0
- data/lib/vagrant-mcs/action/message_will_not_destroy.rb +16 -0
- data/lib/vagrant-mcs/action/package_instance.rb +192 -0
- data/lib/vagrant-mcs/action/read_ssh_info.rb +53 -0
- data/lib/vagrant-mcs/action/read_state.rb +38 -0
- data/lib/vagrant-mcs/action/run_instance.rb +274 -0
- data/lib/vagrant-mcs/action/start_instance.rb +81 -0
- data/lib/vagrant-mcs/action/stop_instance.rb +28 -0
- data/lib/vagrant-mcs/action/terminate_instance.rb +51 -0
- data/lib/vagrant-mcs/action/timed_provision.rb +21 -0
- data/lib/vagrant-mcs/action/wait_for_state.rb +41 -0
- data/lib/vagrant-mcs/action/warn_networks.rb +19 -0
- data/lib/vagrant-mcs/action.rb +210 -0
- data/lib/vagrant-mcs/config.rb +405 -0
- data/lib/vagrant-mcs/errors.rb +43 -0
- data/lib/vagrant-mcs/plugin.rb +73 -0
- data/lib/vagrant-mcs/provider.rb +50 -0
- data/lib/vagrant-mcs/util/elb.rb +56 -0
- data/lib/vagrant-mcs/util/timer.rb +17 -0
- data/lib/vagrant-mcs/version.rb +5 -0
- data/lib/vagrant-mcs.rb +18 -0
- data/locales/en.yml +153 -0
- data/mcs.box +0 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/vagrant-aws/config_spec.rb +225 -0
- data/templates/metadata.json.erb +3 -0
- data/templates/vagrant-aws_package_Vagrantfile.erb +5 -0
- data/vagrant-mcs.gemspec +60 -0
- metadata +172 -0
data/dummy.box
ADDED
Binary file
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# Vagrant MCS Example Box
|
2
|
+
|
3
|
+
Vagrant providers each require a custom provider-specific box format.
|
4
|
+
This folder shows the example contents of a box for the `mcs` provider.
|
5
|
+
To turn this into a box:
|
6
|
+
|
7
|
+
```
|
8
|
+
$ tar cvzf mcs.box ./metadata.json ./Vagrantfile
|
9
|
+
```
|
10
|
+
|
11
|
+
This box works by using Vagrant's built-in Vagrantfile merging to setup
|
12
|
+
defaults for MCS. These defaults can easily be overwritten by higher-level
|
13
|
+
Vagrantfiles (such as project root Vagrantfiles).
|
data/example_box/mcs.box
ADDED
Binary file
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require "fog"
|
2
|
+
require "mos_sdk"
|
3
|
+
require "log4r"
|
4
|
+
|
5
|
+
module VagrantPlugins
|
6
|
+
module MCS
|
7
|
+
module Action
|
8
|
+
# This action connects to MCS, verifies credentials work, and
|
9
|
+
# puts the MCS connection object into the `:mcs_compute` key
|
10
|
+
# in the environment.
|
11
|
+
class ConnectMCS
|
12
|
+
def initialize(app, env)
|
13
|
+
@app = app
|
14
|
+
@logger = Log4r::Logger.new("vagrant_mcs::action::connect_mcs")
|
15
|
+
end
|
16
|
+
|
17
|
+
def call(env)
|
18
|
+
# Get the region we're going to booting up in
|
19
|
+
region = env[:machine].provider_config.region
|
20
|
+
|
21
|
+
# Get the configs
|
22
|
+
region_config = env[:machine].provider_config.get_region_config(region)
|
23
|
+
|
24
|
+
# Build the fog config
|
25
|
+
fog_config = {
|
26
|
+
:provider => :mcs,
|
27
|
+
:region => region
|
28
|
+
}
|
29
|
+
if region_config.use_iam_profile
|
30
|
+
fog_config[:use_iam_profile] = true
|
31
|
+
else
|
32
|
+
fog_config[:mcs_access_key_id] = region_config.access_key_id
|
33
|
+
fog_config[:mcs_secret_access_key] = region_config.secret_access_key
|
34
|
+
fog_config[:mcs_secret_url] = region_config.secret_access_url
|
35
|
+
#fog_config[:mcs_session_token] = region_config.session_token
|
36
|
+
end
|
37
|
+
|
38
|
+
fog_config[:endpoint] = region_config.endpoint if region_config.endpoint
|
39
|
+
fog_config[:version] = region_config.version if region_config.version
|
40
|
+
|
41
|
+
@logger.info("Connecting to MCS...")
|
42
|
+
#env[:mcs_compute] = Fog::Compute.new(fog_config)
|
43
|
+
env[:mcs_compute] = MosSdk::Client.new(region_config.access_key_id,region_config.secret_access_key,region_config.secret_access_url)
|
44
|
+
# env[:mcs_elb] = Fog::MCS::ELB.new(fog_config.except(:provider, :endpoint))
|
45
|
+
|
46
|
+
@app.call(env)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'vagrant-mcs/util/elb'
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module MCS
|
5
|
+
module Action
|
6
|
+
# This registers instance in ELB
|
7
|
+
class ElbDeregisterInstance
|
8
|
+
include ElasticLoadBalancer
|
9
|
+
|
10
|
+
def initialize(app, env)
|
11
|
+
@app = app
|
12
|
+
@logger = Log4r::Logger.new("vagrant_mcs::action::elb_deregister_instance")
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(env)
|
16
|
+
if elb_name = env[:machine].provider_config.elb
|
17
|
+
deregister_instance env, elb_name, env[:machine].id
|
18
|
+
end
|
19
|
+
@app.call(env)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'vagrant-mcs/util/elb'
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module MCS
|
5
|
+
module Action
|
6
|
+
# This registers instance in ELB
|
7
|
+
class ElbRegisterInstance
|
8
|
+
include ElasticLoadBalancer
|
9
|
+
|
10
|
+
def initialize(app, env)
|
11
|
+
@app = app
|
12
|
+
@logger = Log4r::Logger.new("vagrant_mcs::action::elb_register_instance")
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(env)
|
16
|
+
@app.call(env)
|
17
|
+
if elb_name = env[:machine].provider_config.elb
|
18
|
+
register_instance env, elb_name, env[:machine].id
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module MCS
|
3
|
+
module Action
|
4
|
+
# This can be used with "Call" built-in to check if the machine
|
5
|
+
# is created and branch in the middleware.
|
6
|
+
class IsCreated
|
7
|
+
def initialize(app, env)
|
8
|
+
@app = app
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(env)
|
12
|
+
env[:result] = env[:machine].state.id != :not_created
|
13
|
+
@app.call(env)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module MCS
|
3
|
+
module Action
|
4
|
+
# This can be used with "Call" built-in to check if the machine
|
5
|
+
# is stopped and branch in the middleware.
|
6
|
+
class IsStopped
|
7
|
+
def initialize(app, env)
|
8
|
+
@app = app
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(env)
|
12
|
+
env[:result] = env[:machine].state.id == :stopped
|
13
|
+
@app.call(env)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module MCS
|
3
|
+
module Action
|
4
|
+
class MessageAlreadyCreated
|
5
|
+
def initialize(app, env)
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
env[:ui].info(I18n.t("vagrant_mcs.already_status", :status => "created"))
|
11
|
+
@app.call(env)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module MCS
|
3
|
+
module Action
|
4
|
+
class MessageWillNotDestroy
|
5
|
+
def initialize(app, env)
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
env[:ui].info(I18n.t("vagrant_mcs.will_not_destroy", name: env[:machine].name))
|
11
|
+
@app.call(env)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,192 @@
|
|
1
|
+
require "log4r"
|
2
|
+
require 'vagrant/util/template_renderer'
|
3
|
+
require 'vagrant-mcs/util/timer'
|
4
|
+
require 'vagrant/action/general/package'
|
5
|
+
|
6
|
+
module VagrantPlugins
|
7
|
+
module MCS
|
8
|
+
module Action
|
9
|
+
# This action packages a running mcs-based server into an
|
10
|
+
# mcs-based vagrant box. It does so by burning the associated
|
11
|
+
# vagrant-mcs 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_mcs::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[:mcs_compute].servers.get(env[:machine].id)
|
43
|
+
|
44
|
+
env[:ui].info(I18n.t("vagrant_mcs.packaging_instance", :instance_id => server.id))
|
45
|
+
|
46
|
+
# Make the request to MCS 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 mcs 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_mcs.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_mcs.packaging_instance_complete", :time_seconds => env[:metrics]["instance_ready_time"].to_i))
|
91
|
+
rescue Fog::Compute::MCS::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-mcs_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 mcs-vagrant templates
|
185
|
+
def template_root
|
186
|
+
MCS.source_root.join("templates")
|
187
|
+
end
|
188
|
+
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require "log4r"
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module MCS
|
5
|
+
module Action
|
6
|
+
# This action reads the SSH info for the machine and puts it into the
|
7
|
+
# `:machine_ssh_info` key in the environment.
|
8
|
+
class ReadSSHInfo
|
9
|
+
def initialize(app, env)
|
10
|
+
@app = app
|
11
|
+
@logger = Log4r::Logger.new("vagrant_mcs::action::read_ssh_info")
|
12
|
+
end
|
13
|
+
|
14
|
+
def call(env)
|
15
|
+
env[:machine_ssh_info] = read_ssh_info(env[:mcs_compute], env[:machine])
|
16
|
+
|
17
|
+
@app.call(env)
|
18
|
+
end
|
19
|
+
|
20
|
+
def read_ssh_info(mcs, machine)
|
21
|
+
return nil if machine.id.nil?
|
22
|
+
|
23
|
+
# Find the machine
|
24
|
+
server = mcs.servers.get(machine.id)
|
25
|
+
if server.nil?
|
26
|
+
# The machine can't be found
|
27
|
+
@logger.info("Machine couldn't be found, assuming it got destroyed.")
|
28
|
+
machine.id = nil
|
29
|
+
return nil
|
30
|
+
end
|
31
|
+
|
32
|
+
# read attribute override
|
33
|
+
ssh_host_attribute = machine.provider_config.
|
34
|
+
get_region_config(machine.provider_config.region).ssh_host_attribute
|
35
|
+
# default host attributes to try. NOTE: Order matters!
|
36
|
+
ssh_attrs = [:public_ip_address, :dns_name, :private_ip_address]
|
37
|
+
ssh_attrs = (Array(ssh_host_attribute) + ssh_attrs).uniq if ssh_host_attribute
|
38
|
+
# try each attribute, get out on first value
|
39
|
+
host_value = nil
|
40
|
+
while !host_value and attr_name = ssh_attrs.shift
|
41
|
+
begin
|
42
|
+
host_value = server.send(attr_name)
|
43
|
+
rescue NoMethodError
|
44
|
+
@logger.info("SSH host attribute not found #{attr_name}")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
return { :host => host_value, :port => 22 }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|