vagrant-joyent 0.3.0
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.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +201 -0
- data/README.md +30 -0
- data/Rakefile +1 -0
- data/dummy.box +0 -0
- data/example_box/README.md +13 -0
- data/example_box/Vagrantfile +8 -0
- data/example_box/metadata.json +3 -0
- data/lib/vagrant-joyent.rb +18 -0
- data/lib/vagrant-joyent/action.rb +111 -0
- data/lib/vagrant-joyent/action/connect_joyent.rb +33 -0
- data/lib/vagrant-joyent/action/is_created.rb +18 -0
- data/lib/vagrant-joyent/action/message_already_created.rb +16 -0
- data/lib/vagrant-joyent/action/message_not_created.rb +16 -0
- data/lib/vagrant-joyent/action/message_will_not_destroy.rb +16 -0
- data/lib/vagrant-joyent/action/read_ssh_info.rb +71 -0
- data/lib/vagrant-joyent/action/read_state.rb +38 -0
- data/lib/vagrant-joyent/action/run_instance.rb +114 -0
- data/lib/vagrant-joyent/action/sync_folders.rb +60 -0
- data/lib/vagrant-joyent/action/terminate_instance.rb +47 -0
- data/lib/vagrant-joyent/action/warn_networks.rb +19 -0
- data/lib/vagrant-joyent/config.rb +69 -0
- data/lib/vagrant-joyent/errors.rb +19 -0
- data/lib/vagrant-joyent/plugin.rb +73 -0
- data/lib/vagrant-joyent/provider.rb +50 -0
- data/lib/vagrant-joyent/util/timer.rb +17 -0
- data/lib/vagrant-joyent/version.rb +5 -0
- data/locales/en.yml +61 -0
- data/vagrant-joyent.gemspec +63 -0
- metadata +146 -0
@@ -0,0 +1,18 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module Joyent
|
3
|
+
module Action
|
4
|
+
# This can be used with "Call" built-in to check if the machine
|
5
|
+
# is created and branch in the middleware.
|
6
|
+
class IsCreated
|
7
|
+
def initialize(app, env)
|
8
|
+
@app = app
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(env)
|
12
|
+
env[:result] = env[:machine].state.id != :not_created
|
13
|
+
@app.call(env)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module Joyent
|
3
|
+
module Action
|
4
|
+
class MessageAlreadyCreated
|
5
|
+
def initialize(app, env)
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
env[:ui].info(I18n.t("vagrant_joyent.already_created"))
|
11
|
+
@app.call(env)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module Joyent
|
3
|
+
module Action
|
4
|
+
class MessageNotCreated
|
5
|
+
def initialize(app, env)
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
env[:ui].info(I18n.t("vagrant_joyent.not_created"))
|
11
|
+
@app.call(env)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module Joyent
|
3
|
+
module Action
|
4
|
+
class MessageWillNotDestroy
|
5
|
+
def initialize(app, env)
|
6
|
+
@app = app
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
env[:ui].info(I18n.t("vagrant_joyent.will_not_destroy", name: env[:machine].name))
|
11
|
+
@app.call(env)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require "log4r"
|
2
|
+
require 'ipaddr'
|
3
|
+
|
4
|
+
module VagrantPlugins
|
5
|
+
module Joyent
|
6
|
+
module Action
|
7
|
+
# This action reads the SSH info for the machine and puts it into the
|
8
|
+
# `:machine_ssh_info` key in the environment.
|
9
|
+
class ReadSSHInfo
|
10
|
+
def initialize(app, env)
|
11
|
+
@app = app
|
12
|
+
@logger = Log4r::Logger.new("vagrant_joyent::action::read_ssh_info")
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(env)
|
16
|
+
env[:machine_ssh_info] = read_ssh_info(env[:joyent_compute], env[:machine])
|
17
|
+
|
18
|
+
@app.call(env)
|
19
|
+
end
|
20
|
+
|
21
|
+
def is_linklocal(ip)
|
22
|
+
linklocal = IPAddr.new "169.254.0.0/16"
|
23
|
+
return linklocal.include?(ip)
|
24
|
+
end
|
25
|
+
|
26
|
+
def is_loopback(ip)
|
27
|
+
loopback = IPAddr.new "127.0.0.0/8"
|
28
|
+
return loopback.include?(ip)
|
29
|
+
end
|
30
|
+
|
31
|
+
def is_private(ip)
|
32
|
+
block_a = IPAddr.new "10.0.0.0/8"
|
33
|
+
block_b = IPAddr.new "172.16.0.0/12"
|
34
|
+
block_c = IPAddr.new "192.168.0.0/16"
|
35
|
+
return (block_a.include?(ip) or block_b.include?(ip) or block_c.include?(ip))
|
36
|
+
end
|
37
|
+
|
38
|
+
def read_ssh_info(joyent, machine)
|
39
|
+
return nil if machine.id.nil?
|
40
|
+
|
41
|
+
# Find the machine
|
42
|
+
server = joyent.servers.get(machine.id)
|
43
|
+
if server.nil?
|
44
|
+
# The machine can't be found
|
45
|
+
@logger.info("Machine couldn't be found, assuming it got destroyed.")
|
46
|
+
machine.id = nil
|
47
|
+
return nil
|
48
|
+
end
|
49
|
+
|
50
|
+
# IP address to bootstrap
|
51
|
+
bootstrap_ip_addresses = server.ips.select{ |ip| ip and not(is_loopback(ip) or is_linklocal(ip)) }
|
52
|
+
if bootstrap_ip_addresses.count == 1
|
53
|
+
bootstrap_ip_address = bootstrap_ip_addresses.first
|
54
|
+
else
|
55
|
+
bootstrap_ip_address = bootstrap_ip_addresses.find{|ip| not is_private(ip)}
|
56
|
+
end
|
57
|
+
|
58
|
+
config = machine.provider_config
|
59
|
+
|
60
|
+
# Read the DNS info
|
61
|
+
return {
|
62
|
+
:host => bootstrap_ip_address,
|
63
|
+
:port => 22,
|
64
|
+
:private_key_path => config.keyfile,
|
65
|
+
:username => config.ssh_username
|
66
|
+
}
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require "log4r"
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module Joyent
|
5
|
+
module Action
|
6
|
+
# This action reads the state of the machine and puts it in the
|
7
|
+
# `:machine_state_id` key in the environment.
|
8
|
+
class ReadState
|
9
|
+
def initialize(app, env)
|
10
|
+
@app = app
|
11
|
+
@logger = Log4r::Logger.new("vagrant_joyent::action::read_state")
|
12
|
+
end
|
13
|
+
|
14
|
+
def call(env)
|
15
|
+
env[:machine_state_id] = read_state(env[:joyent_compute], env[:machine])
|
16
|
+
|
17
|
+
@app.call(env)
|
18
|
+
end
|
19
|
+
|
20
|
+
def read_state(joyent, machine)
|
21
|
+
return :not_created if machine.id.nil?
|
22
|
+
|
23
|
+
# Find the machine
|
24
|
+
server = joyent.servers.get(machine.id)
|
25
|
+
if server.nil? || [:"shutting-down", :terminated].include?(server.state.to_sym)
|
26
|
+
# The machine can't be found
|
27
|
+
@logger.info("Machine not found or terminated, assuming it got destroyed.")
|
28
|
+
machine.id = nil
|
29
|
+
return :not_created
|
30
|
+
end
|
31
|
+
|
32
|
+
# Return the state
|
33
|
+
return server.state.to_sym
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require "log4r"
|
2
|
+
require 'vagrant/util/retryable'
|
3
|
+
require 'vagrant-joyent/util/timer'
|
4
|
+
|
5
|
+
module VagrantPlugins
|
6
|
+
module Joyent
|
7
|
+
module Action
|
8
|
+
|
9
|
+
# This runs the configured instance.
|
10
|
+
class RunInstance
|
11
|
+
include Vagrant::Util::Retryable
|
12
|
+
|
13
|
+
def initialize(app, env)
|
14
|
+
@app = app
|
15
|
+
@logger = Log4r::Logger.new("vagrant_joyent::action::run_instance")
|
16
|
+
end
|
17
|
+
|
18
|
+
def call(env)
|
19
|
+
# Initialize metrics if they haven't been
|
20
|
+
env[:metrics] ||= {}
|
21
|
+
|
22
|
+
# Get the configs
|
23
|
+
dataset = env[:machine].provider_config.dataset
|
24
|
+
flavor = env[:machine].provider_config.flavor
|
25
|
+
node_name = env[:machine].provider_config.node_name || env[:machine].name
|
26
|
+
keyname = env[:machine].provider_config.joyent_keyname
|
27
|
+
|
28
|
+
# Launch!
|
29
|
+
env[:ui].info(I18n.t("vagrant_joyent.launching_instance"))
|
30
|
+
env[:ui].info(" -- Flavor: #{flavor}")
|
31
|
+
env[:ui].info(" -- Dataset: #{dataset}")
|
32
|
+
env[:ui].info(" -- Node name: #{node_name}")
|
33
|
+
env[:ui].info(" -- Key name: #{keyname}")
|
34
|
+
|
35
|
+
begin
|
36
|
+
options = {
|
37
|
+
:name => node_name,
|
38
|
+
:dataset => dataset,
|
39
|
+
:package => flavor
|
40
|
+
}
|
41
|
+
|
42
|
+
server = env[:joyent_compute].servers.create(options)
|
43
|
+
|
44
|
+
rescue Fog::Compute::Joyent::NotFound => e
|
45
|
+
raise Errors::FogError, :message => e.message
|
46
|
+
rescue Fog::Compute::Joyent::Error => e
|
47
|
+
raise Errors::FogError, :message => e.message
|
48
|
+
end
|
49
|
+
|
50
|
+
# Immediately save the ID since it is created at this point.
|
51
|
+
env[:machine].id = server.id
|
52
|
+
|
53
|
+
# Wait for the instance to be ready first
|
54
|
+
env[:metrics]["instance_ready_time"] = Util::Timer.time do
|
55
|
+
env[:ui].info(I18n.t("vagrant_joyent.waiting_for_ready"))
|
56
|
+
retryable(:on => Fog::Errors::TimeoutError, :tries => 30) do
|
57
|
+
# If we're interrupted don't worry about
|
58
|
+
# waiting
|
59
|
+
next if env[:interrupted]
|
60
|
+
|
61
|
+
# Wait for the server to be ready
|
62
|
+
server.wait_for(2) { ready? }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
@logger.info("Time to instance ready: #{env[:metrics]["instance_ready_time"]}")
|
67
|
+
|
68
|
+
if !env[:interrupted]
|
69
|
+
env[:metrics]["instance_ssh_time"] = Util::Timer.time do
|
70
|
+
# Wait for SSH to be ready.
|
71
|
+
env[:ui].info(I18n.t("vagrant_joyent.waiting_for_ssh"))
|
72
|
+
while true
|
73
|
+
# If we're interrupted then just back
|
74
|
+
# out
|
75
|
+
break if env[:interrupted]
|
76
|
+
break if env[:machine].communicate.ready?
|
77
|
+
sleep 2
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
@logger.info("Time for SSH ready: #{env[:metrics]["instance_ssh_time"]}")
|
82
|
+
|
83
|
+
# Ready and booted!
|
84
|
+
env[:ui].info(I18n.t("vagrant_joyent.ready"))
|
85
|
+
end
|
86
|
+
|
87
|
+
# Terminate the instance if we were interrupted
|
88
|
+
terminate(env) if env[:interrupted]
|
89
|
+
|
90
|
+
@app.call(env)
|
91
|
+
end
|
92
|
+
|
93
|
+
def recover(env)
|
94
|
+
return if env["vagrant.error"].is_a?(Vagrant::Errors::VagrantError)
|
95
|
+
|
96
|
+
if env[:machine].provider.state.id != :not_created
|
97
|
+
# Undo the import
|
98
|
+
terminate(env)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def terminate(env)
|
103
|
+
destroy_env = env.dup
|
104
|
+
destroy_env.delete(:interrupted)
|
105
|
+
destroy_env[:config_validate] = false
|
106
|
+
destroy_env[:force_confirm_destroy] = true
|
107
|
+
env[:action_runner].run(Action.action_destroy, destroy_env)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require "log4r"
|
2
|
+
|
3
|
+
require "vagrant/util/subprocess"
|
4
|
+
|
5
|
+
module VagrantPlugins
|
6
|
+
module Joyent
|
7
|
+
module Action
|
8
|
+
# This middleware uses `rsync` to sync the folders over to the
|
9
|
+
# Joyent instance.
|
10
|
+
class SyncFolders
|
11
|
+
def initialize(app, env)
|
12
|
+
@app = app
|
13
|
+
@logger = Log4r::Logger.new("vagrant_joyent::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
|
+
# Ignore disabled shared folders
|
23
|
+
next if data[:disabled]
|
24
|
+
|
25
|
+
hostpath = File.expand_path(data[:hostpath], env[:root_path])
|
26
|
+
guestpath = data[:guestpath]
|
27
|
+
|
28
|
+
# Make sure there is a trailing slash on the host path to
|
29
|
+
# avoid creating an additional directory with rsync
|
30
|
+
hostpath = "#{hostpath}/" if hostpath !~ /\/$/
|
31
|
+
|
32
|
+
env[:ui].info(I18n.t("vagrant_joyent.rsync_folder",
|
33
|
+
:hostpath => hostpath,
|
34
|
+
:guestpath => guestpath))
|
35
|
+
|
36
|
+
# Create the guest path
|
37
|
+
env[:machine].communicate.sudo("mkdir -p '#{guestpath}'")
|
38
|
+
env[:machine].communicate.sudo(
|
39
|
+
"chown #{ssh_info[:username]} '#{guestpath}'")
|
40
|
+
|
41
|
+
# Rsync over to the guest path using the SSH info
|
42
|
+
command = [
|
43
|
+
"rsync", "--verbose", "--archive", "-z",
|
44
|
+
"-e", "ssh -o StrictHostKeyChecking=no -p #{ssh_info[:port]} -i '#{ssh_info[:keyfile]}'",
|
45
|
+
hostpath,
|
46
|
+
"#{ssh_info[:username]}@#{ssh_info[:host]}:#{guestpath}" ]
|
47
|
+
|
48
|
+
r = Vagrant::Util::Subprocess.execute(*command)
|
49
|
+
if r.exit_code != 0
|
50
|
+
raise Errors::RsyncError,
|
51
|
+
:guestpath => guestpath,
|
52
|
+
:hostpath => hostpath,
|
53
|
+
:stderr => r.stderr
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require "log4r"
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module Joyent
|
5
|
+
module Action
|
6
|
+
# This terminates the running instance.
|
7
|
+
class TerminateInstance
|
8
|
+
def initialize(app, env)
|
9
|
+
@app = app
|
10
|
+
@logger = Log4r::Logger.new("vagrant_joyent::action::run_instance")
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(env)
|
14
|
+
server = env[:joyent_compute].servers.get(env[:machine].id)
|
15
|
+
|
16
|
+
# Destroy the server and remove the tracking ID
|
17
|
+
env[:ui].info(I18n.t("vagrant_joyent.terminating"))
|
18
|
+
|
19
|
+
# Machine must be in a stopped state before it's destroyed.
|
20
|
+
#
|
21
|
+
# More info here:
|
22
|
+
#
|
23
|
+
# https://us-west-1.api.joyentcloud.com/docs#DeleteMachine
|
24
|
+
#
|
25
|
+
server.stop
|
26
|
+
server.destroy
|
27
|
+
|
28
|
+
# Wait for server to be completely gone from invetory
|
29
|
+
while true do
|
30
|
+
ids = []
|
31
|
+
env[:joyent_compute].servers.collect.each { |s|
|
32
|
+
ids << s.id
|
33
|
+
}
|
34
|
+
|
35
|
+
unless ids.include?(env[:machine].id) then
|
36
|
+
break
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
env[:machine].id = nil
|
41
|
+
|
42
|
+
@app.call(env)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module VagrantPlugins
|
2
|
+
module Joyent
|
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_joyent.warn_networks"))
|
12
|
+
end
|
13
|
+
|
14
|
+
@app.call(env)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
#: utf-8 -*-
|
2
|
+
require "vagrant"
|
3
|
+
|
4
|
+
module VagrantPlugins
|
5
|
+
module Joyent
|
6
|
+
class Config < Vagrant.plugin("2", :config)
|
7
|
+
attr_accessor :username
|
8
|
+
attr_accessor :password
|
9
|
+
attr_accessor :keyname
|
10
|
+
attr_accessor :keyfile
|
11
|
+
attr_accessor :api_url
|
12
|
+
attr_accessor :dataset
|
13
|
+
attr_accessor :flavor
|
14
|
+
attr_accessor :node_name
|
15
|
+
attr_accessor :ssh_username
|
16
|
+
attr_accessor :ssl_verify_peer
|
17
|
+
|
18
|
+
def initialize(datacenter_specific=false)
|
19
|
+
@username = UNSET_VALUE
|
20
|
+
@password = UNSET_VALUE
|
21
|
+
@keyname = UNSET_VALUE
|
22
|
+
@keyfile = UNSET_VALUE
|
23
|
+
@api_url = UNSET_VALUE
|
24
|
+
@ssl_verify_peer = UNSET_VALUE
|
25
|
+
@dataset = UNSET_VALUE
|
26
|
+
@flavor = UNSET_VALUE
|
27
|
+
@node_name = UNSET_VALUE
|
28
|
+
@ssh_username = UNSET_VALUE
|
29
|
+
end
|
30
|
+
|
31
|
+
#-------------------------------------------------------------------
|
32
|
+
# Internal methods.
|
33
|
+
#-------------------------------------------------------------------
|
34
|
+
|
35
|
+
def finalize!
|
36
|
+
# API
|
37
|
+
@username = nil if @username == UNSET_VALUE
|
38
|
+
@password = nil if @username == UNSET_VALUE
|
39
|
+
@keyname = nil if @keyname == UNSET_VALUE
|
40
|
+
@keyfile = nil if @keyfile == UNSET_VALUE
|
41
|
+
@api_url = nil if @api_url == UNSET_VALUE
|
42
|
+
|
43
|
+
# SSL
|
44
|
+
@ssl_verify_peer = true if @ssl_verify_peer = UNSET_VALUE
|
45
|
+
|
46
|
+
# Machines
|
47
|
+
@dataset = nil if @dataset == UNSET_VALUE
|
48
|
+
@flavor = "Small 1GB" if @instance_type == UNSET_VALUE
|
49
|
+
@node_name = nil if @node_name == UNSET_VALUE
|
50
|
+
@ssh_username = nil if @ssh_username == UNSET_VALUE
|
51
|
+
end
|
52
|
+
|
53
|
+
def validate(machine)
|
54
|
+
config = self.class.new(true)
|
55
|
+
|
56
|
+
errors = []
|
57
|
+
errors << I18n.t("vagrant_joyent.config.username_required") if config.username.nil?
|
58
|
+
errors << I18n.t("vagrant_joyent.config.keyname_required") if config.keyname.nil?
|
59
|
+
errors << I18n.t("vagrant_joyent.config.keyfile_required") if config.keyfile.nil?
|
60
|
+
errors << I18n.t("vagrant_joyent.config.api_url_required") if config.api_url.nil?
|
61
|
+
errors << I18n.t("vagrant_joyent.config.dataset_required") if config.dataset.nil?
|
62
|
+
errors << I18n.t("vagrant_joyent.config.flavor_required") if config.flavor.nil?
|
63
|
+
errors << I18n.t("vagrant_joyent.config.ssh_username_required") if config.ssh_username.nil?
|
64
|
+
|
65
|
+
{ "Joyent Provider" => errors }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|