vagrant-brightbox 0.1.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.
Files changed (37) hide show
  1. data/.gitignore +15 -0
  2. data/CHANGELOG.md +4 -0
  3. data/Gemfile +10 -0
  4. data/LICENSE +8 -0
  5. data/README.md +217 -0
  6. data/Rakefile +21 -0
  7. data/Vagrantfile.example +105 -0
  8. data/dummy.box +0 -0
  9. data/example_box/README.md +9 -0
  10. data/example_box/metadata.json +3 -0
  11. data/lib/vagrant-brightbox/action/connect_brightbox.rb +53 -0
  12. data/lib/vagrant-brightbox/action/create_server.rb +137 -0
  13. data/lib/vagrant-brightbox/action/delete_server.rb +26 -0
  14. data/lib/vagrant-brightbox/action/forced_halt.rb +27 -0
  15. data/lib/vagrant-brightbox/action/is_created.rb +18 -0
  16. data/lib/vagrant-brightbox/action/is_running.rb +18 -0
  17. data/lib/vagrant-brightbox/action/map_cloud_ip.rb +68 -0
  18. data/lib/vagrant-brightbox/action/message_already_created.rb +16 -0
  19. data/lib/vagrant-brightbox/action/message_not_created.rb +16 -0
  20. data/lib/vagrant-brightbox/action/read_ssh_info.rb +69 -0
  21. data/lib/vagrant-brightbox/action/read_state.rb +38 -0
  22. data/lib/vagrant-brightbox/action/start_server.rb +28 -0
  23. data/lib/vagrant-brightbox/action/sync_folders.rb +58 -0
  24. data/lib/vagrant-brightbox/action/timed_provision.rb +21 -0
  25. data/lib/vagrant-brightbox/action/unsupported.rb +18 -0
  26. data/lib/vagrant-brightbox/action.rb +166 -0
  27. data/lib/vagrant-brightbox/config.rb +268 -0
  28. data/lib/vagrant-brightbox/errors.rb +34 -0
  29. data/lib/vagrant-brightbox/plugin.rb +73 -0
  30. data/lib/vagrant-brightbox/provider.rb +50 -0
  31. data/lib/vagrant-brightbox/util/timer.rb +17 -0
  32. data/lib/vagrant-brightbox/version.rb +5 -0
  33. data/lib/vagrant-brightbox.rb +18 -0
  34. data/locales/en.yml +88 -0
  35. data/spec/vagrant-brightbox/config_spec.rb +179 -0
  36. data/vagrant-brightbox.gemspec +23 -0
  37. metadata +122 -0
@@ -0,0 +1,68 @@
1
+ require 'log4r'
2
+
3
+ module VagrantPlugins
4
+ module Brightbox
5
+ module Action
6
+ class MapCloudIp
7
+
8
+ def initialize(app, env)
9
+ @app = app
10
+ @logger = Log4r::Logger.new("vagrant_brightbox::action::map_cloud_ips")
11
+ end
12
+
13
+ def call(env)
14
+
15
+ @app.call(env)
16
+
17
+ machine = env[:machine]
18
+
19
+ if no_cloud_ips_required?(env[:machine].config.vm.networks)
20
+ @logger.info("No public ipv4 network required")
21
+ return
22
+ end
23
+
24
+ if machine.id.nil?
25
+ @logger.info("No server found - can't map public ips")
26
+ return
27
+ end
28
+
29
+ server = env[:brightbox_compute].servers.get(machine.id)
30
+ if server.nil?
31
+ @logger.info("Machine cannot be found; assuming it got destroyed.")
32
+ machine.id = nil
33
+ return
34
+ end
35
+
36
+ unless server.cloud_ips.empty?
37
+ @logger.info("Server already has public ip address.")
38
+ return
39
+ end
40
+
41
+ target_ip = unallocated_cloud_ip(env[:brightbox_compute].cloud_ips)
42
+
43
+ if target_ip.nil?
44
+ @logger.info("Couldn't allocate a cloud ip")
45
+ env[:ui].info I18n.t("vagrant_brightbox.errors.no_free_cloud_ip")
46
+ return
47
+ end
48
+
49
+ target_ip.map(server)
50
+ env[:ui].info I18n.t("vagrant_brightbox.mapped_cloud_ip", :server => server.id, :cloud_ip => target_ip.public_ip)
51
+
52
+ end
53
+
54
+ def unallocated_cloud_ip(ip_list)
55
+ ip_list.all.detect(ip_list.method(:allocate)) {|ip| !ip.mapped? }
56
+ end
57
+
58
+ def no_cloud_ips_required?(networks)
59
+ networks.any? do |x|
60
+ x.first == :private_network ||
61
+ (x.first == :public_network && element[1][:ipv6])
62
+ end
63
+ end
64
+
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,16 @@
1
+ module VagrantPlugins
2
+ module Brightbox
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_brightbox.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 Brightbox
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_brightbox.not_created"))
11
+ @app.call(env)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,69 @@
1
+ require "log4r"
2
+
3
+ module VagrantPlugins
4
+ module Brightbox
5
+ module Action
6
+ # This action reads the SSH info for the machine and puts it into the
7
+ # `:machine_ssh_info` key in the environment.
8
+ class ReadSSHInfo
9
+ def initialize(app, env)
10
+ @app = app
11
+ @logger = Log4r::Logger.new("vagrant_brightbox::action::read_ssh_info")
12
+ end
13
+
14
+ def call(env)
15
+ env[:machine_ssh_info] = read_ssh_info(env[:brightbox_compute], env[:machine])
16
+
17
+ @app.call(env)
18
+ end
19
+
20
+ def read_ssh_info(brightbox, machine)
21
+ return nil if machine.id.nil?
22
+
23
+ # Find the machine
24
+ server = brightbox.servers.get(machine.id)
25
+ if server.nil?
26
+ # The machine can't be found
27
+ @logger.info("Machine couldn't be found, assuming it got destroyed.")
28
+ machine.id = nil
29
+ return nil
30
+ end
31
+
32
+ # Get the configuration
33
+ region = machine.provider_config.region
34
+ config = machine.provider_config.get_region_config(region)
35
+
36
+ if use_private_network?(machine.config.vm.networks)
37
+ host_name = server.fqdn
38
+ elsif use_ipv6_public_network?(machine.config.vm.networks)
39
+ host_name = "ipv6.#{server.fqdn}"
40
+ elsif server.public_ip_address
41
+ host_name = server.dns_name
42
+ else
43
+ @logger.error("Cannot find public ip address - defaulting to private")
44
+ host_name = server.fqdn
45
+ end
46
+
47
+ # Read the DNS info
48
+ return {
49
+ :host => host_name,
50
+ :port => 22,
51
+ :private_key_path => config.ssh_private_key_path,
52
+ :username => config.ssh_username
53
+ }
54
+ end
55
+
56
+ def use_private_network?(network_structure)
57
+ network_structure.any? {|x| x.first == :private_network }
58
+ end
59
+
60
+ def use_ipv6_public_network?(network_structure)
61
+ network_structure.any? do |element|
62
+ element.first == :public_network && element[1][:ipv6]
63
+ end
64
+ end
65
+
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,38 @@
1
+ require "log4r"
2
+
3
+ module VagrantPlugins
4
+ module Brightbox
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_brightbox::action::read_state")
12
+ end
13
+
14
+ def call(env)
15
+ env[:machine_state_id] = read_state(env[:brightbox_compute], env[:machine])
16
+
17
+ @app.call(env)
18
+ end
19
+
20
+ def read_state(brightbox, machine)
21
+ return :not_created if machine.id.nil?
22
+
23
+ # Find the machine
24
+ server = brightbox.servers.get(machine.id)
25
+ if server.nil? || [:deleted, :deleting, :failed].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,28 @@
1
+ require "log4r"
2
+
3
+ module VagrantPlugins
4
+ module Brightbox
5
+ module Action
6
+ # This starts the server via the api
7
+ class StartServer
8
+ def initialize(app, env)
9
+ @app = app
10
+ @logger = Log4r::Logger.new("vagrant_brightbox::action::start_server")
11
+ end
12
+
13
+ def call(env)
14
+ server = env[:brightbox_compute].servers.get(env[:machine].id)
15
+
16
+ # Make the action idempotent
17
+ unless server.ready?
18
+ # start the server.
19
+ env[:ui].info(I18n.t("vagrant_brightbox.starting_server"))
20
+ server.start
21
+ end
22
+
23
+ @app.call(env)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,58 @@
1
+ require "log4r"
2
+
3
+ require "vagrant/util/subprocess"
4
+
5
+ module VagrantPlugins
6
+ module Brightbox
7
+ module Action
8
+ # This middleware uses `rsync` to sync the folders over to the
9
+ # Brightbox server.
10
+ class SyncFolders
11
+ def initialize(app, env)
12
+ @app = app
13
+ @logger = Log4r::Logger.new("vagrant_brightbox::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
+ hostpath = File.expand_path(data[:hostpath], env[:root_path])
23
+ guestpath = data[:guestpath]
24
+
25
+ # Make sure there is a trailing slash on the host path to
26
+ # avoid creating an additional directory with rsync
27
+ hostpath = "#{hostpath}/" if hostpath !~ /\/$/
28
+
29
+ env[:ui].info(I18n.t("vagrant_brightbox.rsync_folder",
30
+ :hostpath => hostpath,
31
+ :guestpath => guestpath))
32
+
33
+ # Create the guest path
34
+ env[:machine].communicate.sudo("mkdir -p '#{guestpath}'")
35
+ env[:machine].communicate.sudo(
36
+ "chown #{ssh_info[:username]} '#{guestpath}'")
37
+
38
+ # Rsync over to the guest path using the SSH info
39
+ command = [
40
+ "rsync", "--verbose", "--archive", "-z",
41
+ "--exclude", ".vagrant/",
42
+ "-e", "ssh -p #{ssh_info[:port]} -o StrictHostKeyChecking=no -i '#{ssh_info[:private_key_path]}'",
43
+ hostpath,
44
+ "#{ssh_info[:username]}@#{ssh_info[:host]}:#{guestpath}"]
45
+
46
+ r = Vagrant::Util::Subprocess.execute(*command)
47
+ if r.exit_code != 0
48
+ raise Errors::RsyncError,
49
+ :guestpath => guestpath,
50
+ :hostpath => hostpath,
51
+ :stderr => r.stderr
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,21 @@
1
+ require "vagrant-brightbox/util/timer"
2
+
3
+ module VagrantPlugins
4
+ module Brightbox
5
+ module Action
6
+ # This is the same as the builtin provision except it times the
7
+ # provisioner runs.
8
+ class TimedProvision < Vagrant::Action::Builtin::Provision
9
+ def run_provisioner(env, p)
10
+ timer = Util::Timer.time do
11
+ super
12
+ end
13
+
14
+ env[:metrics] ||= {}
15
+ env[:metrics]["provisioner_times"] ||= []
16
+ env[:metrics]["provisioner_times"] << [p.class.to_s, timer]
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,18 @@
1
+ module VagrantPlugins
2
+ module Brightbox
3
+ module Action
4
+ class Unsupported
5
+ def initialize(app, env)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ env[:ui].warn(I18n.t("vagrant_brightbox.unsupported"))
11
+
12
+ @app.call(env)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+
@@ -0,0 +1,166 @@
1
+ require "pathname"
2
+
3
+ require "vagrant/action/builder"
4
+
5
+ module VagrantPlugins
6
+ module Brightbox
7
+ module Action
8
+ # Include the built-in modules so we can use them as top-level things.
9
+ include Vagrant::Action::Builtin
10
+
11
+ # This action is called to destroy the remote machine.
12
+ def self.action_destroy
13
+ Vagrant::Action::Builder.new.tap do |b|
14
+ b.use ConfigValidate
15
+ b.use Call, IsCreated do |env, b2|
16
+ if env[:result]
17
+ b2.use ConnectBrightbox
18
+ b2.use DeleteServer
19
+ else
20
+ b2.use MessageNotCreated
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+ # This action is called to halt the server - gracefully or by force.
27
+ def self.action_halt
28
+ Vagrant::Action::Builder.new.tap do |b|
29
+ b.use ConfigValidate
30
+ b.use Call, IsCreated do |env, b2|
31
+ if env[:result]
32
+ b2.use Call, GracefulHalt, :inactive, :active do |env2, b3|
33
+ if !env2[:result]
34
+ b3.use ConnectBrightbox
35
+ b3.use ForcedHalt
36
+ end
37
+ end
38
+ else
39
+ b2.use MessageNotCreated
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+ # This action reloads the machine - essentially shutting it down
46
+ # and bringing it back up again in the new configuration.
47
+ def self.action_reload
48
+ Vagrant::Action::Builder.new.tap do |b|
49
+ b.use Call, IsCreated do |env, b2|
50
+ if env[:result]
51
+ b2.use action_halt
52
+ b2.use action_up
53
+ else
54
+ b2.use MessageNotCreated
55
+ end
56
+ end
57
+ end
58
+ end
59
+
60
+ # This action is called when `vagrant provision` is called.
61
+ def self.action_provision
62
+ Vagrant::Action::Builder.new.tap do |b|
63
+ b.use ConfigValidate
64
+ b.use Call, IsCreated do |env, b2|
65
+ if env[:result]
66
+ b2.use Provision
67
+ b2.use SyncFolders
68
+ else
69
+ b2.use MessageNotCreated
70
+ end
71
+ end
72
+ end
73
+ end
74
+
75
+
76
+ # This action is called to read the SSH info of the machine. The
77
+ # resulting state is expected to be put into the `:machine_ssh_info`
78
+ # key.
79
+ def self.action_read_ssh_info
80
+ Vagrant::Action::Builder.new.tap do |b|
81
+ b.use ConfigValidate
82
+ b.use ConnectBrightbox
83
+ b.use ReadSSHInfo
84
+ end
85
+ end
86
+
87
+ # This action is called to read the state of the machine. The
88
+ # resulting state is expected to be put into the `:machine_state_id`
89
+ # key.
90
+ def self.action_read_state
91
+ Vagrant::Action::Builder.new.tap do |b|
92
+ b.use ConfigValidate
93
+ b.use ConnectBrightbox
94
+ b.use ReadState
95
+ end
96
+ end
97
+
98
+ def self.action_ssh
99
+ Vagrant::Action::Builder.new.tap do |b|
100
+ b.use ConfigValidate
101
+ b.use Call, IsCreated do |env, b2|
102
+ if env[:result]
103
+ b2.use SSHExec
104
+ else
105
+ b2.use MessageNotCreated
106
+ end
107
+ end
108
+ end
109
+ end
110
+
111
+ def self.action_up
112
+ Vagrant::Action::Builder.new.tap do |b|
113
+ b.use ConfigValidate
114
+ b.use ConnectBrightbox
115
+ b.use Call, IsCreated do |env, b2|
116
+ if env[:result]
117
+ b2.use Call, IsRunning do |env2, b3|
118
+ if env2[:result]
119
+ b3.use MessageAlreadyCreated
120
+ else
121
+ b3.use StartServer
122
+ b3.use MapCloudIp
123
+ end
124
+ end
125
+ else
126
+ b2.use Provision
127
+ b2.use SyncFolders
128
+ b2.use CreateServer
129
+ b2.use MapCloudIp
130
+ end
131
+ end
132
+ end
133
+ end
134
+
135
+ def self.action_package
136
+ Vagrant::Action::Builder.new.tap do |b|
137
+ b.use Unsupported
138
+ end
139
+ end
140
+
141
+ class << self
142
+ alias action_resume action_package
143
+ alias action_suspend action_package
144
+ end
145
+
146
+
147
+
148
+ # The autoload farm
149
+ action_root = Pathname.new(File.expand_path("../action", __FILE__))
150
+ autoload :ConnectBrightbox, action_root.join("connect_brightbox")
151
+ autoload :CreateServer, action_root.join("create_server")
152
+ autoload :DeleteServer, action_root.join("delete_server")
153
+ autoload :IsCreated, action_root.join("is_created")
154
+ autoload :IsRunning, action_root.join("is_running")
155
+ autoload :MessageAlreadyCreated, action_root.join("message_already_created")
156
+ autoload :MessageNotCreated, action_root.join("message_not_created")
157
+ autoload :ReadSSHInfo, action_root.join("read_ssh_info")
158
+ autoload :ReadState, action_root.join("read_state")
159
+ autoload :SyncFolders, action_root.join("sync_folders")
160
+ autoload :MapCloudIp, action_root.join("map_cloud_ip")
161
+ autoload :ForcedHalt, action_root.join("forced_halt")
162
+ autoload :StartServer, action_root.join("start_server")
163
+ autoload :Unsupported, action_root.join("unsupported")
164
+ end
165
+ end
166
+ end