vagrant-vultr_pro 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.projections.json +4 -0
- data/CHANGELOG.md +23 -0
- data/Gemfile +9 -0
- data/LICENSE.md +20 -0
- data/README.md +116 -0
- data/Rakefile +17 -0
- data/box/vultr.box +0 -0
- data/features/support/env.rb +11 -0
- data/features/vagrant-vultr.feature +78 -0
- data/lib/vagrant-vultr/action/check_state.rb +20 -0
- data/lib/vagrant-vultr/action/create.rb +73 -0
- data/lib/vagrant-vultr/action/destroy.rb +30 -0
- data/lib/vagrant-vultr/action/power_off.rb +25 -0
- data/lib/vagrant-vultr/action/power_on.rb +32 -0
- data/lib/vagrant-vultr/action/reload.rb +32 -0
- data/lib/vagrant-vultr/action/setup_ssh_key.rb +31 -0
- data/lib/vagrant-vultr/action.rb +132 -0
- data/lib/vagrant-vultr/config.rb +76 -0
- data/lib/vagrant-vultr/helpers/client.rb +156 -0
- data/lib/vagrant-vultr/plugin.rb +18 -0
- data/lib/vagrant-vultr/provider.rb +48 -0
- data/lib/vagrant-vultr_pro.rb +12 -0
- data/lib/vultr/version.rb +10 -0
- data/lib/vultr/vultr.rb +888 -0
- data/vagrant-vultr_pro.gemspec +24 -0
- metadata +152 -0
@@ -0,0 +1,76 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module Vultr
|
3
|
+
class Config < Vagrant.plugin(2, :config)
|
4
|
+
attr_accessor :token
|
5
|
+
attr_accessor :region
|
6
|
+
attr_accessor :os
|
7
|
+
attr_accessor :snapshot
|
8
|
+
attr_accessor :plan
|
9
|
+
attr_accessor :enable_ipv6
|
10
|
+
attr_accessor :enable_private_network
|
11
|
+
attr_accessor :label
|
12
|
+
attr_accessor :tag
|
13
|
+
attr_accessor :hostname
|
14
|
+
attr_accessor :timeout
|
15
|
+
attr_accessor :ssh_key
|
16
|
+
attr_accessor :startup_script
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
@token = UNSET_VALUE
|
20
|
+
@region = UNSET_VALUE
|
21
|
+
@os = UNSET_VALUE
|
22
|
+
@snapshot = UNSET_VALUE
|
23
|
+
@plan = UNSET_VALUE
|
24
|
+
@enable_ipv6 = UNSET_VALUE
|
25
|
+
@enable_private_network = UNSET_VALUE
|
26
|
+
@label = UNSET_VALUE
|
27
|
+
@tag = UNSET_VALUE
|
28
|
+
@hostname = UNSET_VALUE
|
29
|
+
@timeout = UNSET_VALUE
|
30
|
+
@ssh_key = UNSET_VALUE
|
31
|
+
@startup_script = UNSET_VALUE
|
32
|
+
end
|
33
|
+
|
34
|
+
def finalize!
|
35
|
+
@token = ENV['VULTR_TOKEN'] if @token == UNSET_VALUE
|
36
|
+
@region = 'Seattle' if @region == UNSET_VALUE
|
37
|
+
@os = 'Ubuntu 14.04 x64' if @os == UNSET_VALUE && @snapshot == UNSET_VALUE
|
38
|
+
@plan = '768 MB RAM,15 GB SSD,1.00 TB BW' if @plan == UNSET_VALUE
|
39
|
+
@snapshot = nil if @snapshot == UNSET_VALUE
|
40
|
+
@enable_ipv6 = 'no' if @enable_ipv6 == UNSET_VALUE
|
41
|
+
@enable_private_network = 'no' if @enable_private_network == UNSET_VALUE
|
42
|
+
@label = '' if @label == UNSET_VALUE
|
43
|
+
@tag = '' if @tag == UNSET_VALUE
|
44
|
+
@hostname = '' if @hostname == UNSET_VALUE
|
45
|
+
@script = '' if @script == UNSET_VALUE
|
46
|
+
@timeout = 300 if @timeout == UNSET_VALUE
|
47
|
+
@ssh_key = 'vagrant' if @ssh_key == UNSET_VALUE
|
48
|
+
@startup_script = '' if @startup_script == UNSET_VALUE
|
49
|
+
end
|
50
|
+
|
51
|
+
def validate(machine)
|
52
|
+
errors = []
|
53
|
+
|
54
|
+
key = machine.config.ssh.private_key_path
|
55
|
+
key = key.first if key.is_a?(Array)
|
56
|
+
if !key
|
57
|
+
errors << 'You have to specify config.ssh.private_key_path.'
|
58
|
+
elsif !File.file?(File.expand_path("#{key}.pub", machine.env.root_path))
|
59
|
+
errors << "Cannot find SSH public key: #{key}.pub."
|
60
|
+
end
|
61
|
+
|
62
|
+
if both_os_and_snapshot_provided?
|
63
|
+
errors << 'You have to specify one of provider.os or provider.snapshot.'
|
64
|
+
end
|
65
|
+
|
66
|
+
{'vultr' => errors}
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def both_os_and_snapshot_provided?
|
72
|
+
@os != UNSET_VALUE && @snapshot
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
require 'vultr/vultr'
|
2
|
+
require 'vagrant/util/retryable'
|
3
|
+
|
4
|
+
module VagrantPlugins
|
5
|
+
module Vultr
|
6
|
+
module Helpers
|
7
|
+
module Client
|
8
|
+
def client
|
9
|
+
@client ||= ApiClient.new(@machine.provider_config.token, @machine.provider_config.timeout)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
class ApiClient
|
15
|
+
include Vagrant::Util::Retryable
|
16
|
+
|
17
|
+
TimeoutError = Class.new(StandardError)
|
18
|
+
|
19
|
+
def initialize(token, timeout)
|
20
|
+
::Vultr.api_key = token
|
21
|
+
@timeout = timeout || 300
|
22
|
+
end
|
23
|
+
|
24
|
+
def servers
|
25
|
+
servers = request { ::Vultr::Server.list }
|
26
|
+
servers = servers.values if servers.any?
|
27
|
+
|
28
|
+
servers
|
29
|
+
end
|
30
|
+
|
31
|
+
def server(sub_id)
|
32
|
+
servers.find { |server| server['SUBID'] == sub_id }
|
33
|
+
end
|
34
|
+
|
35
|
+
def create_server(attributes)
|
36
|
+
params = {
|
37
|
+
DCID: region_id(attributes[:region]),
|
38
|
+
VPSPLANID: vps_plan_id(attributes[:plan]),
|
39
|
+
SSHKEYID: ssh_key_id(attributes[:ssh_key_name]),
|
40
|
+
SCRIPTID: startup_script_id(attributes[:startup_script_name]),
|
41
|
+
enable_ipv6: attributes[:enable_ipv6],
|
42
|
+
enable_private_network: attributes[:enable_private_network],
|
43
|
+
label: attributes[:label],
|
44
|
+
tag: attributes[:tag],
|
45
|
+
hostname: attributes[:hostname]
|
46
|
+
}
|
47
|
+
|
48
|
+
if attributes[:snapshot]
|
49
|
+
params.merge!(OSID: os_id('Snapshot'), SNAPSHOTID: attributes[:snapshot])
|
50
|
+
else
|
51
|
+
params.merge!(OSID: os_id(attributes[:os]))
|
52
|
+
end
|
53
|
+
|
54
|
+
request { ::Vultr::Server.create(params) }['SUBID']
|
55
|
+
end
|
56
|
+
|
57
|
+
def start_server(sub_id)
|
58
|
+
request { ::Vultr::Server.start(SUBID: sub_id) }
|
59
|
+
end
|
60
|
+
|
61
|
+
def reboot_server(sub_id)
|
62
|
+
request { ::Vultr::Server.reboot(SUBID: sub_id) }
|
63
|
+
end
|
64
|
+
|
65
|
+
def stop_server(sub_id)
|
66
|
+
request { ::Vultr::Server.halt(SUBID: sub_id) }
|
67
|
+
end
|
68
|
+
|
69
|
+
def destroy_server(sub_id)
|
70
|
+
request { ::Vultr::Server.destroy(SUBID: sub_id) }
|
71
|
+
end
|
72
|
+
|
73
|
+
def os_id(os)
|
74
|
+
oses = request { ::Vultr::OS.list }
|
75
|
+
oses.values.find { |o| o['name'] == os }['OSID']
|
76
|
+
end
|
77
|
+
|
78
|
+
def region_id(region)
|
79
|
+
regions = request { ::Vultr::Regions.list }
|
80
|
+
regions.values.find { |r| r['name'] == region }['DCID']
|
81
|
+
end
|
82
|
+
|
83
|
+
def vps_plan_id(plan)
|
84
|
+
plans = request { ::Vultr::Plans.list }
|
85
|
+
plans.values.find { |p| p['name'] == plan }['VPSPLANID']
|
86
|
+
end
|
87
|
+
|
88
|
+
def startup_script_id(startup_script_name)
|
89
|
+
scripts = request { ::Vultr::StartupScript.list }
|
90
|
+
script = scripts.values.find { |s| s['name'] == startup_script_name }
|
91
|
+
script['SCRIPTID'] if script
|
92
|
+
end
|
93
|
+
|
94
|
+
def ssh_key_id(ssh_key_name)
|
95
|
+
ssh_keys = request { ::Vultr::SSHKey.list }
|
96
|
+
ssh_key = ssh_keys.values.find { |s| s['name'] == ssh_key_name }
|
97
|
+
ssh_key['SSHKEYID'] if ssh_key
|
98
|
+
end
|
99
|
+
|
100
|
+
def create_ssh_key(name, key)
|
101
|
+
request { ::Vultr::SSHKey.create(name: name, ssh_key: key) }['SSHKEYID']
|
102
|
+
end
|
103
|
+
|
104
|
+
def wait_to_activate(sub_id)
|
105
|
+
wait_until do
|
106
|
+
# it might be not shown in API for some reason
|
107
|
+
server = server(sub_id)
|
108
|
+
server && server['status'] == 'active'
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def wait_to_power_on(sub_id)
|
113
|
+
wait_until do
|
114
|
+
# it might be not shown in API for some reason
|
115
|
+
server = server(sub_id)
|
116
|
+
server && server['status'] == 'active' && server['power_status'] == 'running' && server['server_state'] == 'ok'
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def wait_to_destroy(sub_id)
|
121
|
+
wait_until { !server(sub_id) }
|
122
|
+
end
|
123
|
+
|
124
|
+
# @todo Fix the case when SSH key is not ready so it asks for password
|
125
|
+
# @todo Extract away from client?
|
126
|
+
def wait_for_ssh(machine)
|
127
|
+
# SSH may be unreachable after server is started
|
128
|
+
wait_until(Errno::ENETUNREACH) do
|
129
|
+
machine.communicate.wait_for_ready(@timeout)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
private
|
134
|
+
|
135
|
+
def request
|
136
|
+
if interval = ENV['VULTR_RATE_LIMIT_INTERVAL_MS']
|
137
|
+
sleep interval.to_f / 1000
|
138
|
+
end
|
139
|
+
|
140
|
+
response = yield
|
141
|
+
if response[:status] != 200
|
142
|
+
raise "API request failed: #{response[:result]}."
|
143
|
+
else
|
144
|
+
response[:result]
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def wait_until(exception = TimeoutError)
|
149
|
+
retryable(tries: @timeout, sleep: 1, on: exception) do
|
150
|
+
yield or raise exception
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module Vultr
|
3
|
+
class Plugin < Vagrant.plugin(2)
|
4
|
+
name 'vagrant-vultr_pro'
|
5
|
+
description 'Plugin allows to use Vultr as provider'
|
6
|
+
|
7
|
+
config(:vultr, :provider) do
|
8
|
+
require_relative 'config'
|
9
|
+
Config
|
10
|
+
end
|
11
|
+
|
12
|
+
provider(:vultr) do
|
13
|
+
require_relative 'provider'
|
14
|
+
Provider
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'vagrant-vultr/helpers/client'
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module Vultr
|
5
|
+
class Provider < Vagrant.plugin(2, :provider)
|
6
|
+
include Helpers::Client
|
7
|
+
|
8
|
+
def initialize(machine)
|
9
|
+
@machine = machine
|
10
|
+
@client = client
|
11
|
+
end
|
12
|
+
|
13
|
+
def action(name)
|
14
|
+
return unless Action.respond_to?(name)
|
15
|
+
Action.__send__(name)
|
16
|
+
end
|
17
|
+
|
18
|
+
def state
|
19
|
+
server = @client.server(@machine.id)
|
20
|
+
|
21
|
+
if server
|
22
|
+
if server['status'] == 'active' && server['power_status'] == 'running'
|
23
|
+
state = :active
|
24
|
+
else
|
25
|
+
state = :off
|
26
|
+
end
|
27
|
+
else
|
28
|
+
state = :not_created
|
29
|
+
end
|
30
|
+
|
31
|
+
long = short = state.to_s
|
32
|
+
Vagrant::MachineState.new(state, short, long)
|
33
|
+
end
|
34
|
+
|
35
|
+
def ssh_info
|
36
|
+
server = @client.server(@machine.id)
|
37
|
+
return if server['status'] != 'active' && server['power_status'] != 'running'
|
38
|
+
|
39
|
+
{
|
40
|
+
host: server['main_ip'],
|
41
|
+
port: '22',
|
42
|
+
username: 'root',
|
43
|
+
PasswordAuthentication: 'no'
|
44
|
+
}
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|