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.
@@ -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