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.
- data/.env-example +4 -0
- data/.gitignore +17 -0
- data/.rspec +1 -0
- data/Gemfile +7 -0
- data/LICENSE +10 -0
- data/README.md +110 -0
- data/Rakefile +21 -0
- data/a.rb +1 -0
- data/actionio-dummy.box +0 -0
- data/data/cacert.pem +3895 -0
- data/example_box/README.md +13 -0
- data/example_box/metadata.json +3 -0
- data/lib/vagrant-actionio.rb +18 -0
- data/lib/vagrant-actionio/action.rb +152 -0
- data/lib/vagrant-actionio/action/connect_actionio.rb +31 -0
- data/lib/vagrant-actionio/action/is_created.rb +18 -0
- data/lib/vagrant-actionio/action/is_running.rb +18 -0
- data/lib/vagrant-actionio/action/is_stopped.rb +18 -0
- data/lib/vagrant-actionio/action/is_terminated.rb +18 -0
- data/lib/vagrant-actionio/action/message_already_created.rb +16 -0
- data/lib/vagrant-actionio/action/message_already_terminated.rb +16 -0
- data/lib/vagrant-actionio/action/message_cannot_terminate.rb +16 -0
- data/lib/vagrant-actionio/action/message_not_created.rb +16 -0
- data/lib/vagrant-actionio/action/message_not_running.rb +16 -0
- data/lib/vagrant-actionio/action/message_provisioning_not_yet_supported.rb +16 -0
- data/lib/vagrant-actionio/action/read_ssh_info.rb +53 -0
- data/lib/vagrant-actionio/action/read_state.rb +36 -0
- data/lib/vagrant-actionio/action/remove_machine_id.rb +19 -0
- data/lib/vagrant-actionio/action/run_instance.rb +94 -0
- data/lib/vagrant-actionio/action/start_instance.rb +56 -0
- data/lib/vagrant-actionio/action/stop_instance.rb +56 -0
- data/lib/vagrant-actionio/action/sync_folders.rb +57 -0
- data/lib/vagrant-actionio/action/terminate_instance.rb +57 -0
- data/lib/vagrant-actionio/action/timed_provision.rb +21 -0
- data/lib/vagrant-actionio/action/warn_networks.rb +19 -0
- data/lib/vagrant-actionio/config.rb +75 -0
- data/lib/vagrant-actionio/connection.rb +70 -0
- data/lib/vagrant-actionio/errors.rb +35 -0
- data/lib/vagrant-actionio/plugin.rb +73 -0
- data/lib/vagrant-actionio/provider.rb +50 -0
- data/lib/vagrant-actionio/util/env.rb +12 -0
- data/lib/vagrant-actionio/util/timer.rb +17 -0
- data/lib/vagrant-actionio/version.rb +5 -0
- data/locales/en.yml +121 -0
- data/spec/vagrant-actionio/action/read_ssh_info_spec.rb +58 -0
- data/spec/vagrant-actionio/action/read_state_spec.rb +46 -0
- data/spec/vagrant-actionio/action/run_instance_spec.rb +24 -0
- data/spec/vagrant-actionio/action/start_instance_spec.rb +21 -0
- data/spec/vagrant-actionio/action/stop_instance_spec.rb +21 -0
- data/spec/vagrant-actionio/action/terminate_instance_spec.rb +21 -0
- data/spec/vagrant-actionio/config_spec.rb +47 -0
- data/spec/vagrant-actionio/connection_spec.rb +105 -0
- data/vagrant-actionio.gemspec +59 -0
- 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,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
|
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
|
+
|