vagrant-actionio 0.0.9

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