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.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +21 -0
  3. data/.rspec +1 -0
  4. data/CHANGELOG.md +92 -0
  5. data/Gemfile +12 -0
  6. data/LICENSE +8 -0
  7. data/README.md +292 -0
  8. data/Rakefile +21 -0
  9. data/dummy.box +0 -0
  10. data/example_box/README.md +13 -0
  11. data/example_box/mcs.box +0 -0
  12. data/example_box/metadata.json +3 -0
  13. data/lib/vagrant-mcs/action/connect_mcs.rb +51 -0
  14. data/lib/vagrant-mcs/action/elb_deregister_instance.rb +24 -0
  15. data/lib/vagrant-mcs/action/elb_register_instance.rb +24 -0
  16. data/lib/vagrant-mcs/action/is_created.rb +18 -0
  17. data/lib/vagrant-mcs/action/is_stopped.rb +18 -0
  18. data/lib/vagrant-mcs/action/message_already_created.rb +16 -0
  19. data/lib/vagrant-mcs/action/message_not_created.rb +16 -0
  20. data/lib/vagrant-mcs/action/message_will_not_destroy.rb +16 -0
  21. data/lib/vagrant-mcs/action/package_instance.rb +192 -0
  22. data/lib/vagrant-mcs/action/read_ssh_info.rb +53 -0
  23. data/lib/vagrant-mcs/action/read_state.rb +38 -0
  24. data/lib/vagrant-mcs/action/run_instance.rb +274 -0
  25. data/lib/vagrant-mcs/action/start_instance.rb +81 -0
  26. data/lib/vagrant-mcs/action/stop_instance.rb +28 -0
  27. data/lib/vagrant-mcs/action/terminate_instance.rb +51 -0
  28. data/lib/vagrant-mcs/action/timed_provision.rb +21 -0
  29. data/lib/vagrant-mcs/action/wait_for_state.rb +41 -0
  30. data/lib/vagrant-mcs/action/warn_networks.rb +19 -0
  31. data/lib/vagrant-mcs/action.rb +210 -0
  32. data/lib/vagrant-mcs/config.rb +405 -0
  33. data/lib/vagrant-mcs/errors.rb +43 -0
  34. data/lib/vagrant-mcs/plugin.rb +73 -0
  35. data/lib/vagrant-mcs/provider.rb +50 -0
  36. data/lib/vagrant-mcs/util/elb.rb +56 -0
  37. data/lib/vagrant-mcs/util/timer.rb +17 -0
  38. data/lib/vagrant-mcs/version.rb +5 -0
  39. data/lib/vagrant-mcs.rb +18 -0
  40. data/locales/en.yml +153 -0
  41. data/mcs.box +0 -0
  42. data/spec/spec_helper.rb +1 -0
  43. data/spec/vagrant-aws/config_spec.rb +225 -0
  44. data/templates/metadata.json.erb +3 -0
  45. data/templates/vagrant-aws_package_Vagrantfile.erb +5 -0
  46. data/vagrant-mcs.gemspec +60 -0
  47. 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).
Binary file
@@ -0,0 +1,3 @@
1
+ {
2
+ "provider": "mcs"
3
+ }
@@ -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 MessageNotCreated
5
+ def initialize(app, env)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ env[:ui].info(I18n.t("vagrant_mcs.not_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