vagrant-joyent 0.3.0

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