vagrant-actionio 0.0.9

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 (54) hide show
  1. data/.env-example +4 -0
  2. data/.gitignore +17 -0
  3. data/.rspec +1 -0
  4. data/Gemfile +7 -0
  5. data/LICENSE +10 -0
  6. data/README.md +110 -0
  7. data/Rakefile +21 -0
  8. data/a.rb +1 -0
  9. data/actionio-dummy.box +0 -0
  10. data/data/cacert.pem +3895 -0
  11. data/example_box/README.md +13 -0
  12. data/example_box/metadata.json +3 -0
  13. data/lib/vagrant-actionio.rb +18 -0
  14. data/lib/vagrant-actionio/action.rb +152 -0
  15. data/lib/vagrant-actionio/action/connect_actionio.rb +31 -0
  16. data/lib/vagrant-actionio/action/is_created.rb +18 -0
  17. data/lib/vagrant-actionio/action/is_running.rb +18 -0
  18. data/lib/vagrant-actionio/action/is_stopped.rb +18 -0
  19. data/lib/vagrant-actionio/action/is_terminated.rb +18 -0
  20. data/lib/vagrant-actionio/action/message_already_created.rb +16 -0
  21. data/lib/vagrant-actionio/action/message_already_terminated.rb +16 -0
  22. data/lib/vagrant-actionio/action/message_cannot_terminate.rb +16 -0
  23. data/lib/vagrant-actionio/action/message_not_created.rb +16 -0
  24. data/lib/vagrant-actionio/action/message_not_running.rb +16 -0
  25. data/lib/vagrant-actionio/action/message_provisioning_not_yet_supported.rb +16 -0
  26. data/lib/vagrant-actionio/action/read_ssh_info.rb +53 -0
  27. data/lib/vagrant-actionio/action/read_state.rb +36 -0
  28. data/lib/vagrant-actionio/action/remove_machine_id.rb +19 -0
  29. data/lib/vagrant-actionio/action/run_instance.rb +94 -0
  30. data/lib/vagrant-actionio/action/start_instance.rb +56 -0
  31. data/lib/vagrant-actionio/action/stop_instance.rb +56 -0
  32. data/lib/vagrant-actionio/action/sync_folders.rb +57 -0
  33. data/lib/vagrant-actionio/action/terminate_instance.rb +57 -0
  34. data/lib/vagrant-actionio/action/timed_provision.rb +21 -0
  35. data/lib/vagrant-actionio/action/warn_networks.rb +19 -0
  36. data/lib/vagrant-actionio/config.rb +75 -0
  37. data/lib/vagrant-actionio/connection.rb +70 -0
  38. data/lib/vagrant-actionio/errors.rb +35 -0
  39. data/lib/vagrant-actionio/plugin.rb +73 -0
  40. data/lib/vagrant-actionio/provider.rb +50 -0
  41. data/lib/vagrant-actionio/util/env.rb +12 -0
  42. data/lib/vagrant-actionio/util/timer.rb +17 -0
  43. data/lib/vagrant-actionio/version.rb +5 -0
  44. data/locales/en.yml +121 -0
  45. data/spec/vagrant-actionio/action/read_ssh_info_spec.rb +58 -0
  46. data/spec/vagrant-actionio/action/read_state_spec.rb +46 -0
  47. data/spec/vagrant-actionio/action/run_instance_spec.rb +24 -0
  48. data/spec/vagrant-actionio/action/start_instance_spec.rb +21 -0
  49. data/spec/vagrant-actionio/action/stop_instance_spec.rb +21 -0
  50. data/spec/vagrant-actionio/action/terminate_instance_spec.rb +21 -0
  51. data/spec/vagrant-actionio/config_spec.rb +47 -0
  52. data/spec/vagrant-actionio/connection_spec.rb +105 -0
  53. data/vagrant-actionio.gemspec +59 -0
  54. metadata +2882 -0
@@ -0,0 +1,36 @@
1
+ require 'log4r'
2
+ require 'vagrant-actionio/errors'
3
+
4
+ module VagrantPlugins
5
+ module ActionIO
6
+ module Action
7
+ # This action reads the state of the machine and puts it in the
8
+ # `:machine_state_id` key in the environment.
9
+ class ReadState
10
+ def initialize(app, env)
11
+ @app = app
12
+ @logger = Log4r::Logger.new("vagrant_actionio::action::read_state")
13
+ end
14
+
15
+ def call(env)
16
+ env[:machine_state_id] = read_state(env[:actionio], env[:machine])
17
+
18
+ @app.call(env)
19
+ end
20
+
21
+ def read_state(actionio, machine)
22
+ return :not_created if machine.id.nil?
23
+
24
+ # Find the box
25
+ state = actionio.fetch_box_state(machine.id)
26
+ if state.nil?
27
+ @logger.info("Box not found on Action.IO, assuming it got destroyed.")
28
+ machine.id = nil
29
+ return :not_created
30
+ end
31
+ state
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,19 @@
1
+ module VagrantPlugins
2
+ module ActionIO
3
+ module Action
4
+ # This can be used with "Call" built-in to check if the machine
5
+ # is terminated and branch in the middleware.
6
+ class RemoveMachineId
7
+ def initialize(app, env)
8
+ @app = app
9
+ end
10
+
11
+ def call(env)
12
+ env[:machine].id = nil
13
+
14
+ @app.call(env)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,94 @@
1
+ require 'log4r'
2
+ require 'vagrant/util/retryable'
3
+ require 'vagrant-actionio/util/timer'
4
+ require 'vagrant-actionio/errors'
5
+ require 'securerandom'
6
+
7
+ module VagrantPlugins
8
+ module ActionIO
9
+ module Action
10
+ # This runs the configured instance.
11
+ class RunInstance
12
+ include Vagrant::Util::Retryable
13
+
14
+ def initialize(app, env)
15
+ @app = app
16
+ @logger = Log4r::Logger.new('vagrant_actionio::action::run_instance')
17
+ end
18
+
19
+ def call(env)
20
+ # Initialize metrics if they haven't been
21
+ env[:metrics] ||= {}
22
+
23
+ actionio = env[:actionio]
24
+ machine = env[:machine]
25
+
26
+ # Get the configs
27
+ config = machine.provider_config
28
+ box_name = "vagrant-#{SecureRandom.hex 5}"
29
+ region = config.region
30
+ stack = config.stack
31
+
32
+ # Launch!
33
+ env[:ui].info I18n.t('vagrant_actionio.launching_box')
34
+ env[:ui].info " -- Box Name: #{box_name}"
35
+ env[:ui].info " -- Region: #{region}"
36
+ env[:ui].info " -- Stack: #{stack}"
37
+
38
+ create_box(actionio, machine, box_name, region, stack)
39
+
40
+ # Poll server to check whether the box is ready
41
+ env[:ui].info(I18n.t('vagrant_actionio.starting_box'))
42
+
43
+ # Wait 15 seconds first
44
+ sleep 15.0
45
+
46
+ wait_for_box_to_start(env)
47
+
48
+ if !env[:interrupted]
49
+ # Ready and booted!
50
+ env[:ui].info(I18n.t('vagrant_actionio.ready'))
51
+ end
52
+
53
+ # Terminate the instance if we were interrupted
54
+ #terminate(env) if env[:interrupted]
55
+
56
+ @logger.info("Time to instance ready: #{env[:metrics]["instance_ready_time"]}")
57
+
58
+ @app.call(env)
59
+ end
60
+
61
+ def create_box(actionio, machine, box_name, region, stack)
62
+ response = actionio.request(:post, '/boxes', params: { box: { name: box_name, region: region, box_template: stack } })
63
+
64
+ # save box id
65
+ machine.id = response.parsed['box']['id']
66
+ end
67
+
68
+ def wait_for_box_to_start(env)
69
+ actionio = env[:actionio]
70
+ machine = env[:machine]
71
+ env[:metrics]['instance_ready_time'] = Util::Timer.time do
72
+ retryable(on: Errors::BoxNotYetStartedError, tries: 10, sleep: 5.0) do
73
+ # If we're interrupted don't worry about waiting
74
+ next if env[:interrupted]
75
+
76
+ # check for the box's status
77
+ if actionio.fetch_box_state(machine.id) != :running
78
+ raise Errors::BoxNotYetStartedError
79
+ end
80
+ end
81
+ end
82
+ end
83
+
84
+ def terminate(env)
85
+ destroy_env = env.dup
86
+ destroy_env.delete(:interrupted)
87
+ destroy_env[:config_validate] = false
88
+ destroy_env[:force_confirm_destroy] = true
89
+ env[:action_runner].run(Action.action_destroy, destroy_env)
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,56 @@
1
+ require 'log4r'
2
+ require 'vagrant/util/retryable'
3
+ require 'vagrant-actionio/errors'
4
+
5
+ module VagrantPlugins
6
+ module ActionIO
7
+ module Action
8
+ # This runs the configured instance.
9
+ class StartInstance
10
+ include Vagrant::Util::Retryable
11
+
12
+ def initialize(app, env)
13
+ @app = app
14
+ @logger = Log4r::Logger.new('vagrant_actionio::action::start_instance')
15
+ end
16
+
17
+ def call(env)
18
+ actionio = env[:actionio]
19
+ machine = env[:machine]
20
+
21
+ start_box(actionio, machine)
22
+
23
+ # Poll server to check whether the box is ready
24
+ env[:ui].info(I18n.t('vagrant_actionio.starting_box'))
25
+
26
+ # Wait 10 seconds first
27
+ sleep 10.0
28
+
29
+ wait_for_box_to_start(env)
30
+
31
+ env[:ui].info(I18n.t('vagrant_actionio.ready'))
32
+
33
+ @app.call(env)
34
+ end
35
+
36
+ def start_box(actionio, machine)
37
+ actionio.request(:put, "/boxes/#{machine.id}/start")
38
+ end
39
+
40
+ def wait_for_box_to_start(env)
41
+ actionio = env[:actionio]
42
+ machine = env[:machine]
43
+ retryable(on: Errors::BoxNotYetStartedError, tries: 10, sleep: 3.0) do
44
+ # If we're interrupted don't worry about waiting
45
+ next if env[:interrupted]
46
+
47
+ # check for the box's status
48
+ if actionio.fetch_box_state(machine.id) != :running
49
+ raise Errors::BoxNotYetStartedError
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,56 @@
1
+ require 'log4r'
2
+ require 'vagrant/util/retryable'
3
+ require 'vagrant-actionio/errors'
4
+
5
+ module VagrantPlugins
6
+ module ActionIO
7
+ module Action
8
+ # This runs the configured instance.
9
+ class StopInstance
10
+ include Vagrant::Util::Retryable
11
+
12
+ def initialize(app, env)
13
+ @app = app
14
+ @logger = Log4r::Logger.new('vagrant_actionio::action::stop_instance')
15
+ end
16
+
17
+ def call(env)
18
+ actionio = env[:actionio]
19
+ machine = env[:machine]
20
+
21
+ stop_box(actionio, machine)
22
+
23
+ # Poll server to check whether the box is ready
24
+ env[:ui].info(I18n.t('vagrant_actionio.stopping_box'))
25
+
26
+ # Wait 10 seconds first
27
+ sleep 10.0
28
+
29
+ wait_for_box_to_stop(env)
30
+
31
+ env[:ui].info(I18n.t('vagrant_actionio.stopped'))
32
+
33
+ @app.call(env)
34
+ end
35
+
36
+ def stop_box(actionio, machine)
37
+ actionio.request(:put, "/boxes/#{machine.id}/stop")
38
+ end
39
+
40
+ def wait_for_box_to_stop(env)
41
+ actionio = env[:actionio]
42
+ machine = env[:machine]
43
+ retryable(on: Errors::BoxNotYetStoppedError, tries: 10, sleep: 3.0) do
44
+ # If we're interrupted don't worry about waiting
45
+ next if env[:interrupted]
46
+
47
+ # check for the box's status
48
+ if actionio.fetch_box_state(machine.id) != :stopped
49
+ raise Errors::BoxNotYetStoppedError
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,57 @@
1
+ require 'log4r'
2
+
3
+ require 'vagrant/util/subprocess'
4
+
5
+ module VagrantPlugins
6
+ module ActionIO
7
+ module Action
8
+ # This middleware uses `rsync` to sync the folders over to the
9
+ # Action.IO box.
10
+ class SyncFolders
11
+ def initialize(app, env)
12
+ @app = app
13
+ @logger = Log4r::Logger.new("vagrant_actionio::action::sync_folders")
14
+ end
15
+
16
+ def call(env)
17
+ @app.call(env)
18
+
19
+ ssh_info = env[:machine].ssh_info
20
+
21
+ env[:machine].config.vm.synced_folders.each do |id, data|
22
+ hostpath = File.expand_path(data[:hostpath], env[:root_path])
23
+ guestpath = File.join('/home/action', data[:guestpath])
24
+
25
+ # Make sure there is a trailing slash on the host path to
26
+ # avoid creating an additional directory with rsync
27
+ hostpath = "#{hostpath}/" if hostpath !~ /\/$/
28
+
29
+ env[:ui].info(I18n.t("vagrant_actionio.rsync_folder",
30
+ :hostpath => hostpath,
31
+ :guestpath => guestpath))
32
+
33
+ # Create the guest path
34
+ env[:machine].communicate.execute("mkdir -p '#{guestpath}'")
35
+ env[:machine].communicate.execute(
36
+ "chown #{ssh_info[:username]} '#{guestpath}'")
37
+
38
+ # Rsync over to the guest path using the SSH info
39
+ command = [
40
+ "rsync", "--verbose", "--archive", "-z",
41
+ "-e", "ssh -p #{ssh_info[:port]} -i '#{ssh_info[:private_key_path]}' -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o LogLevel=FATAL",
42
+ hostpath,
43
+ "#{ssh_info[:username]}@#{ssh_info[:host]}:#{guestpath}"]
44
+
45
+ r = Vagrant::Util::Subprocess.execute(*command)
46
+ if r.exit_code != 0
47
+ raise Errors::RsyncError,
48
+ :guestpath => guestpath,
49
+ :hostpath => hostpath,
50
+ :stderr => r.stderr
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,57 @@
1
+ require 'log4r'
2
+ require 'vagrant/util/retryable'
3
+ require 'vagrant-actionio/errors'
4
+
5
+ module VagrantPlugins
6
+ module ActionIO
7
+ module Action
8
+ # This terminates the running instance.
9
+ class TerminateInstance
10
+ include Vagrant::Util::Retryable
11
+
12
+ def initialize(app, env)
13
+ @app = app
14
+ @logger = Log4r::Logger.new('vagrant_actionio::action::terminate_instance')
15
+ end
16
+
17
+ def call(env)
18
+ actionio = env[:actionio]
19
+ machine = env[:machine]
20
+
21
+ # Destroy the server and remove the tracking ID
22
+ env[:ui].info(I18n.t('vagrant_actionio.terminating_box'))
23
+ terminate_box(actionio, machine)
24
+
25
+ # Wait 15 seconds first
26
+ sleep 15.0
27
+
28
+ wait_for_box_to_terminate(env)
29
+
30
+ machine.id = nil
31
+
32
+ env[:ui].info(I18n.t('vagrant_actionio.terminated'))
33
+
34
+ @app.call(env)
35
+ end
36
+
37
+ def terminate_box(actionio, machine)
38
+ actionio.request(:delete, "/boxes/#{machine.id}")
39
+ end
40
+
41
+ def wait_for_box_to_terminate(env)
42
+ actionio = env[:actionio]
43
+ machine = env[:machine]
44
+ retryable(on: Errors::BoxNotYetTerminatedError, tries: 10, sleep: 3.0) do
45
+ # If we're interrupted don't worry about waiting
46
+ next if env[:interrupted]
47
+
48
+ # check for the box's status
49
+ if actionio.fetch_box_state(machine.id) != :terminated
50
+ raise Errors::BoxNotYetTerminatedError
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,21 @@
1
+ require 'vagrant-actionio/util/timer'
2
+
3
+ module VagrantPlugins
4
+ module ActionIO
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, prov)
10
+ timer = Util::Timer.time do
11
+ super
12
+ end
13
+
14
+ env[:metrics] ||= {}
15
+ env[:metrics]["provisioner_times"] ||= []
16
+ env[:metrics]["provisioner_times"] << [prov.class.to_s, timer]
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,19 @@
1
+ module VagrantPlugins
2
+ module ActionIO
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_actionio.warn_networks'))
12
+ end
13
+
14
+ @app.call(env)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,75 @@
1
+ require 'vagrant'
2
+
3
+ module VagrantPlugins
4
+ module ActionIO
5
+ class Config < Vagrant.plugin('2', :config)
6
+ # The access token for accessing Action.IO API.
7
+ #
8
+ # @return [String]
9
+ attr_accessor :access_token
10
+
11
+ # The name of the Action.IO region in which to create the box.
12
+ #
13
+ # @return [String]
14
+ attr_accessor :region
15
+
16
+ # The name of the Action.IO base stack (box template) to create the box.
17
+ #
18
+ # @return [String]
19
+ attr_accessor :stack
20
+
21
+ # The path to the SSH private key to use with the Action.IO box.
22
+ # This overrides the `config.ssh.private_key_path` variable.
23
+ #
24
+ # @return [String]
25
+ attr_accessor :ssh_private_key_path
26
+
27
+ def initialize(region_specific=false)
28
+ @access_token = UNSET_VALUE
29
+ @region = UNSET_VALUE
30
+ @stack = UNSET_VALUE
31
+ @ssh_private_key_path = UNSET_VALUE
32
+
33
+ # Internal state (prefix with __ so they aren't automatically
34
+ # merged)
35
+ @__finalized = false
36
+ end
37
+
38
+ #-------------------------------------------------------------------
39
+ # Internal methods.
40
+ #-------------------------------------------------------------------
41
+
42
+ def finalize!
43
+ # The access token default to nil
44
+ @access_token = nil if @access_token == UNSET_VALUE
45
+
46
+ # Default region is usw-1
47
+ @region = 'us-west-1' if @region == UNSET_VALUE
48
+
49
+ # Box base stack defaults to rails
50
+ @stack = 'rails' if @stack == UNSET_VALUE
51
+
52
+ # The SSH values by default are nil, and the top-level config
53
+ # `config.ssh` values are used.
54
+ @ssh_private_key_path = nil if @ssh_private_key_path == UNSET_VALUE
55
+
56
+ # Mark that we finalized
57
+ @__finalized = true
58
+ end
59
+
60
+ def validate(machine)
61
+ errors = []
62
+
63
+ errors << I18n.t('vagrant_actionio.config.access_token_required') if @access_token.nil?
64
+ errors << I18n.t('vagrant_actionio.config.region_required') if @region.nil?
65
+ errors << I18n.t('vagrant_actionio.config.ssh_private_key_path_required') if @ssh_private_key_path.nil?
66
+
67
+ if @ssh_private_key_path && !File.file?(File.expand_path(@ssh_private_key_path, machine.env.root_path))
68
+ errors << I18n.t('vagrant_actionio.config.private_key_missing')
69
+ end
70
+
71
+ { 'Action.IO Provider' => errors }
72
+ end
73
+ end
74
+ end
75
+ end