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,70 @@
1
+ require 'vagrant-actionio/util/env'
2
+ require 'vagrant-actionio/errors'
3
+ require 'vagrant-actionio/version'
4
+ require 'oauth2'
5
+
6
+ ENV['SSL_CERT_FILE'] = File.join(File.expand_path('../../../', __FILE__), '/data/cacert.pem')
7
+
8
+ module VagrantPlugins
9
+ module ActionIO
10
+ class Connection
11
+ OAUTH_CLIENT_ID = Util::Env.read_with_default('VAGRANT_ACTIONIO_OAUTH_ID', '414b8765a91db88e3d9d2a391eb19117a652b23ec7c1222fd61ddb59d0298072')
12
+ OAUTH_CLIENT_SECRET = Util::Env.read_with_default('VAGRANT_ACTIONIO_OAUTH_SECRET', 'd64a2c76e05126366d9627f165978a2a810c6b853c853df805e22f7390e59950')
13
+ VERIFY_SSL = ENV['VAGRANT_ACTIONIO_VERIFY_SSL'] != 'false'
14
+ HOST = Util::Env.read_with_default('VAGRANT_ACTIONIO_HOST', 'https://www.action.io')
15
+ API_PATH_PREFIX = '/api/v0'
16
+ USER_AGENT = "Vagrant-ActionIO/#{VERSION} (Vagrant #{Vagrant::VERSION}; #{RUBY_DESCRIPTION})"
17
+
18
+ attr_accessor :client, :token
19
+
20
+ def initialize(access_token_string)
21
+ options = { site: HOST }
22
+ options[:ssl] = { verify_mode: OpenSSL::SSL::VERIFY_NONE } if !VERIFY_SSL
23
+ @client = OAuth2::Client.new(OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET, options)
24
+ @token = OAuth2::AccessToken.new(client, access_token_string)
25
+ end
26
+
27
+ def request(verb, path, options={})
28
+ options = { parse: :json }.merge options
29
+ options[:headers] ||= {}
30
+ options[:headers]['User-Agent'] = USER_AGENT
31
+
32
+ @token.request verb.to_sym, "#{API_PATH_PREFIX}#{path}", options
33
+ end
34
+
35
+ def verify_access_token
36
+ response = request(:get, '/scopes')
37
+ rescue => e
38
+ if e.response && e.response.status == 401
39
+ raise Errors::APIError, 'invalid_access_token'
40
+ else
41
+ raise e
42
+ end
43
+ else
44
+ if response.status == 200
45
+ json = JSON.parse(response.body)
46
+ if json.kind_of?(Hash) && json['scopes'].split.include?('boxes')
47
+ return
48
+ else
49
+ raise Errors::APIError, 'invalid_access_token_scope'
50
+ end
51
+ end
52
+ end
53
+
54
+ def fetch_box_state(box_id)
55
+ begin
56
+ response = request(:get, "/boxes/#{box_id}")
57
+ rescue => e
58
+ if e.respond_to?(:response) && e.response.status == 404
59
+ # The box can't be found
60
+ return nil
61
+ else
62
+ raise e
63
+ end
64
+ end
65
+
66
+ response.parsed['box']['state'].to_sym
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,35 @@
1
+ require 'vagrant'
2
+
3
+ module VagrantPlugins
4
+ module ActionIO
5
+ module Errors
6
+ class VagrantActionIOError < Vagrant::Errors::VagrantError
7
+ error_namespace('vagrant_actionio.errors')
8
+ end
9
+
10
+ class APIError < VagrantActionIOError
11
+ error_key(:api_error)
12
+ end
13
+
14
+ class BoxNotYetStartedError < VagrantActionIOError
15
+ error_key(:box_not_yet_started_error)
16
+ end
17
+
18
+ class BoxNotYetStoppedError < VagrantActionIOError
19
+ error_key(:box_not_yet_stopped_error)
20
+ end
21
+
22
+ class BoxNotYetTerminatedError < VagrantActionIOError
23
+ error_key(:box_not_yet_terminated_error)
24
+ end
25
+
26
+ class RsyncError < VagrantActionIOError
27
+ error_key(:rsync_error)
28
+ end
29
+
30
+ class TimeoutError < VagrantActionIOError
31
+ error_key(:timeout_error)
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,73 @@
1
+ begin
2
+ require 'vagrant'
3
+ rescue LoadError
4
+ raise 'The Vagrant Action.IO plugin must be run within Vagrant.'
5
+ end
6
+
7
+ # This is a sanity check to make sure no one is attempting to install
8
+ # this into an early Vagrant version.
9
+ if Vagrant::VERSION < '1.1.0'
10
+ raise 'The Vagrant Action.IO plugin is only compatible with Vagrant 1.1+'
11
+ end
12
+
13
+ module VagrantPlugins
14
+ module ActionIO
15
+ class Plugin < Vagrant.plugin('2')
16
+ name 'Action.IO'
17
+ description <<-DESC
18
+ This plugin installs a provider that allows Vagrant to manage
19
+ boxes in Action.IO.
20
+ DESC
21
+
22
+ config(:actionio, :provider) do
23
+ require_relative 'config'
24
+ Config
25
+ end
26
+
27
+ provider(:actionio) do
28
+ # Setup logging and i18n
29
+ setup_logging
30
+ setup_i18n
31
+
32
+ # Return the provider
33
+ require_relative 'provider'
34
+ Provider
35
+ end
36
+
37
+ # This initializes the internationalization strings.
38
+ def self.setup_i18n
39
+ I18n.load_path << File.expand_path('locales/en.yml', ActionIO.source_root)
40
+ I18n.reload!
41
+ end
42
+
43
+ # This sets up our log level to be whatever VAGRANT_LOG is.
44
+ def self.setup_logging
45
+ require 'log4r'
46
+
47
+ level = nil
48
+ begin
49
+ level = Log4r.const_get(ENV['VAGRANT_LOG'].upcase)
50
+ rescue NameError
51
+ # This means that the logging constant wasn't found,
52
+ # which is fine. We just keep `level` as `nil`. But
53
+ # we tell the user.
54
+ level = nil
55
+ end
56
+
57
+ # Some constants, such as "true" resolve to booleans, so the
58
+ # above error checking doesn't catch it. This will check to make
59
+ # sure that the log level is an integer, as Log4r requires.
60
+ level = nil if !level.is_a?(Integer)
61
+
62
+ # Set the logging level on all "vagrant" namespaced
63
+ # logs as long as we have a valid level.
64
+ if level
65
+ logger = Log4r::Logger.new('vagrant_actionio')
66
+ logger.outputters = Log4r::Outputter.stderr
67
+ logger.level = level
68
+ logger = nil
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,50 @@
1
+ require 'log4r'
2
+ require 'vagrant'
3
+
4
+ module VagrantPlugins
5
+ module ActionIO
6
+ class Provider < Vagrant.plugin('2', :provider)
7
+ def initialize(machine)
8
+ @machine = machine
9
+ end
10
+
11
+ def action(name)
12
+ # Attempt to get the action method from the Action class if it
13
+ # exists, otherwise return nil to show that we don't support the
14
+ # given action.
15
+ action_method = "action_#{name}"
16
+ return Action.send(action_method) if Action.respond_to?(action_method)
17
+ nil
18
+ end
19
+
20
+ def ssh_info
21
+ # Run a custom action called 'read_ssh_info' which does what it
22
+ # says and puts the resulting SSH info into the `:machine_ssh_info`
23
+ # key in the environment.
24
+ env = @machine.action('read_ssh_info')
25
+ env[:machine_ssh_info]
26
+ end
27
+
28
+ def state
29
+ # Run a custom action we define called 'read_state' which does
30
+ # what it says. It puts the state in the `:machine_state_id`
31
+ # key in the environment.
32
+ env = @machine.action('read_state')
33
+
34
+ state_id = env[:machine_state_id]
35
+
36
+ # Get the short and long description
37
+ short = I18n.t("vagrant_actionio.states.short_#{state_id}")
38
+ long = I18n.t("vagrant_actionio.states.long_#{state_id}")
39
+
40
+ # Return the MachineState object
41
+ Vagrant::MachineState.new(state_id, short, long)
42
+ end
43
+
44
+ def to_s
45
+ id = @machine.id.nil? ? 'new' : @machine.id
46
+ "Action.IO (#{id})"
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,12 @@
1
+ module VagrantPlugins
2
+ module ActionIO
3
+ module Util
4
+ class Env
5
+ def self.read_with_default(env_var, default)
6
+ value = ENV[env_var]
7
+ value.nil? ? default : value
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,17 @@
1
+ module VagrantPlugins
2
+ module ActionIO
3
+ module Util
4
+ class Timer
5
+ # A basic utility method that times the execution of the given
6
+ # block and returns it.
7
+ def self.time
8
+ start_time = Time.now.to_f
9
+ yield
10
+ end_time = Time.now.to_f
11
+
12
+ end_time - start_time
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,5 @@
1
+ module VagrantPlugins
2
+ module ActionIO
3
+ VERSION = '0.0.9'
4
+ end
5
+ end
data/locales/en.yml ADDED
@@ -0,0 +1,121 @@
1
+ en:
2
+ vagrant_actionio:
3
+ already_created: |-
4
+ The box already exists on Action.IO.
5
+ already_terminated: |-
6
+ The box is already terminated on Action.IO.
7
+ cannot_terminate: |-
8
+ The box needs to be in either "running" or "stopped" state to be terminatable.
9
+ launching_box: |-
10
+ Launching a box on Action.IO with the following settings...
11
+ not_created: |-
12
+ Your box on Action.IO is not created. Please create your box by running `vagrant up` first.
13
+ not_running: |-
14
+ Your box on Action.IO is not running. Please start your box by running `vagrant up` first.
15
+ provisioning_not_yet_supported: |-
16
+ Vagrant provisioning is coming soon, but not yet supported. Please check https://github.com/action-io/vagrant-actionio for updates.
17
+ ready: |-
18
+ Your box on Action.IO is running and ready for use!
19
+ rsync_folder: |-
20
+ Rsyncing folder: %{hostpath} => %{guestpath}
21
+ starting_box: |-
22
+ Starting the box on Action.IO...
23
+ stopped: |-
24
+ Your box on Action.IO is stopped.
25
+ stopping_box: |-
26
+ Stopping the box on Action.IO...
27
+ terminated: |-
28
+ Your box on Action.IO is terminated.
29
+ terminating_box: |-
30
+ Terminating the box on Action.IO...
31
+ warn_networks: |-
32
+ Warning! The Action.IO provider doesn't support any of the Vagrant
33
+ high-level network configurations (`config.vm.network`). They
34
+ will be silently ignored.
35
+
36
+ config:
37
+ access_token_required: |-
38
+ An access token must be specified via "access_token"
39
+
40
+ private_key_missing: |-
41
+ The specified SSH private key could not be found
42
+
43
+ region_required: |-
44
+ A region must be specified via "region"
45
+
46
+ ssh_private_key_path_required: |-
47
+ A path to an ssh private key must be specified via "ssh_private_key_path"
48
+
49
+ errors:
50
+ api_error: |-
51
+ There was an error talking to Action.IO. The error message is shown below:
52
+
53
+ %{message}
54
+
55
+ box_not_yet_started_error: |-
56
+ Box is not yet started.
57
+
58
+ box_not_yet_stopped_error: |-
59
+ Box is not yet stopped.
60
+
61
+ box_not_yet_terminated_error: |-
62
+ Box is not yet terminated.
63
+
64
+ invalid_access_token: |-
65
+ Access token is invalid.
66
+
67
+ invalid_access_token_scope: |-
68
+ Access token does not have "boxes" scope.
69
+
70
+ rsync_error: |-
71
+ There was an error when attemping to rsync a shared folder.
72
+ Please inspect the error message below for more info.
73
+
74
+ Host path: %{hostpath}
75
+ Guest path: %{guestpath}
76
+ Error: %{stderr}
77
+
78
+ timeout_error: |-
79
+ Box creation timed out.
80
+
81
+ states:
82
+ short_not_created: |-
83
+ not created
84
+ long_not_created: |-
85
+ The Action.IO box is not created. Run `vagrant up` to create it.
86
+
87
+ short_provisioning: |-
88
+ provisioning
89
+ long_provisioning: |-
90
+ The Action.IO box is being created.
91
+
92
+ short_running: |-
93
+ running
94
+ long_running: |-
95
+ The Action.IO box is running. To stop this machine, you can run
96
+ `vagrant halt`. To destroy the machine, you can run `vagrant destroy`.
97
+
98
+ short_starting: |-
99
+ starting
100
+ long_starting: |-
101
+ The Action.IO box is starting.
102
+
103
+ short_stopped: |-
104
+ stopped
105
+ long_stopped: |-
106
+ The Action.IO box is stopped. Run `vagrant up` to start it.
107
+
108
+ short_stopping: |-
109
+ stopping
110
+ long_stopping: |-
111
+ The Action.IO box is stopping.
112
+
113
+ short_terminated: |-
114
+ terminated
115
+ long_terminated: |-
116
+ The Action.IO box is terminated.
117
+
118
+ short_terminating: |-
119
+ terminating
120
+ long_terminating: |-
121
+ The Action.IO box is terminating.
@@ -0,0 +1,58 @@
1
+ require 'vagrant-actionio/action/read_ssh_info'
2
+ require 'ostruct'
3
+
4
+ describe VagrantPlugins::ActionIO::Action::ReadSSHInfo do
5
+ let(:app) { double 'app', call: nil }
6
+ let(:instance) { VagrantPlugins::ActionIO::Action::ReadSSHInfo.new(app, env) }
7
+
8
+ context 'when machine id is nil' do
9
+ let(:machine) { double 'machine', id: nil }
10
+ let(:env) { { actionio: nil, machine: machine } }
11
+
12
+ it 'returns nil' do
13
+ instance.call(env)
14
+ expect(env[:machine_ssh_info]).to be_nil
15
+ end
16
+ end
17
+
18
+ context 'when machine id is not nil' do
19
+ let(:machine) { OpenStruct.new(id: 123) }
20
+ let!(:actionio) { double 'connection', request: nil }
21
+ let(:env) { { actionio: actionio, machine: machine } }
22
+
23
+ context 'when request is successful' do
24
+ before do
25
+ json = '{"box":{"id":123,"host":"foo-box-123.usw1.actionbox.io","port":12345}}'
26
+ response = double 'response', status: 200, body: json, parsed: JSON.parse(json)
27
+ actionio.should_receive(:request).with(:get, '/boxes/123').and_return response
28
+ machine.stub_chain(:provider_config, :ssh_private_key_path).and_return '/home/action/.ssh/id_rsa'
29
+ end
30
+
31
+ it 'makes a get request to /boxes/:id and returns a hash containing the ssh info' do
32
+ instance.call(env)
33
+ expect(env[:machine_ssh_info]).to eq({
34
+ host: 'foo-box-123.usw1.actionbox.io',
35
+ port: '12345',
36
+ private_key_path: '/home/action/.ssh/id_rsa',
37
+ username: 'action'
38
+ })
39
+ end
40
+ end
41
+
42
+ context 'when request returns 404' do
43
+ before do
44
+ response = double 'response', status: 404
45
+ error = StandardError.new('request error')
46
+ error.stub(:response) { response }
47
+ actionio.should_receive(:request).with(:get, '/boxes/123').and_raise error
48
+ end
49
+
50
+ it 'sets machine id to be nil and returns nil' do
51
+ instance.call(env)
52
+ expect(env[:machine].id).to be_nil
53
+ expect(env[:machine_ssh_info]).to be_nil
54
+ end
55
+ end
56
+ end
57
+ end
58
+