vagrantup 0.3.4 → 0.4.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 +4 -4
- data/Gemfile +2 -2
- data/README.md +2 -2
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/config/default.rb +13 -3
- data/lib/vagrant.rb +10 -13
- data/lib/vagrant/actions/base.rb +14 -2
- data/lib/vagrant/actions/box/download.rb +2 -7
- data/lib/vagrant/actions/box/verify.rb +1 -1
- data/lib/vagrant/actions/runner.rb +0 -1
- data/lib/vagrant/actions/vm/boot.rb +2 -6
- data/lib/vagrant/actions/vm/customize.rb +7 -5
- data/lib/vagrant/actions/vm/destroy.rb +4 -3
- data/lib/vagrant/actions/vm/down.rb +6 -3
- data/lib/vagrant/actions/vm/export.rb +2 -4
- data/lib/vagrant/actions/vm/forward_ports.rb +77 -16
- data/lib/vagrant/actions/vm/halt.rb +10 -2
- data/lib/vagrant/actions/vm/import.rb +2 -4
- data/lib/vagrant/actions/vm/move_hard_drive.rb +2 -2
- data/lib/vagrant/actions/vm/network.rb +120 -0
- data/lib/vagrant/actions/vm/package.rb +11 -7
- data/lib/vagrant/actions/vm/provision.rb +3 -3
- data/lib/vagrant/actions/vm/reload.rb +2 -9
- data/lib/vagrant/actions/vm/shared_folders.rb +19 -39
- data/lib/vagrant/actions/vm/start.rb +10 -2
- data/lib/vagrant/actions/vm/up.rb +5 -6
- data/lib/vagrant/active_list.rb +23 -13
- data/lib/vagrant/box.rb +2 -2
- data/lib/vagrant/busy.rb +3 -3
- data/lib/vagrant/command.rb +2 -2
- data/lib/vagrant/commands/base.rb +40 -20
- data/lib/vagrant/commands/destroy.rb +17 -3
- data/lib/vagrant/commands/halt.rb +23 -3
- data/lib/vagrant/commands/package.rb +54 -14
- data/lib/vagrant/commands/provision.rb +31 -0
- data/lib/vagrant/commands/reload.rb +16 -3
- data/lib/vagrant/commands/resume.rb +16 -3
- data/lib/vagrant/commands/ssh.rb +25 -3
- data/lib/vagrant/commands/ssh_config.rb +20 -5
- data/lib/vagrant/commands/status.rb +107 -40
- data/lib/vagrant/commands/suspend.rb +16 -3
- data/lib/vagrant/commands/up.rb +26 -7
- data/lib/vagrant/config.rb +82 -12
- data/lib/vagrant/downloaders/base.rb +8 -1
- data/lib/vagrant/downloaders/http.rb +31 -19
- data/lib/vagrant/environment.rb +146 -49
- data/lib/vagrant/provisioners/base.rb +19 -5
- data/lib/vagrant/provisioners/chef.rb +12 -4
- data/lib/vagrant/provisioners/chef_server.rb +13 -6
- data/lib/vagrant/provisioners/chef_solo.rb +7 -3
- data/lib/vagrant/resource_logger.rb +126 -0
- data/lib/vagrant/ssh.rb +109 -8
- data/lib/vagrant/systems/base.rb +70 -0
- data/lib/vagrant/systems/linux.rb +137 -0
- data/lib/vagrant/util.rb +1 -45
- data/lib/vagrant/util/error_helper.rb +13 -0
- data/lib/vagrant/util/glob_loader.rb +22 -0
- data/lib/vagrant/util/output_helper.rb +9 -0
- data/lib/vagrant/util/plain_logger.rb +12 -0
- data/lib/vagrant/util/platform.rb +7 -2
- data/lib/vagrant/util/template_renderer.rb +2 -2
- data/lib/vagrant/util/translator.rb +35 -0
- data/lib/vagrant/vm.rb +91 -10
- data/templates/crontab_entry.erb +1 -0
- data/templates/network_entry.erb +8 -0
- data/templates/ssh_config.erb +1 -0
- data/templates/{errors.yml → strings.yml} +111 -3
- data/templates/sync.erb +14 -0
- data/test/test_helper.rb +46 -3
- data/test/vagrant/actions/box/download_test.rb +0 -17
- data/test/vagrant/actions/vm/boot_test.rb +3 -10
- data/test/vagrant/actions/vm/customize_test.rb +6 -0
- data/test/vagrant/actions/vm/destroy_test.rb +6 -5
- data/test/vagrant/actions/vm/down_test.rb +5 -11
- data/test/vagrant/actions/vm/export_test.rb +1 -0
- data/test/vagrant/actions/vm/forward_ports_test.rb +92 -15
- data/test/vagrant/actions/vm/halt_test.rb +36 -4
- data/test/vagrant/actions/vm/import_test.rb +2 -0
- data/test/vagrant/actions/vm/network_test.rb +237 -0
- data/test/vagrant/actions/vm/package_test.rb +35 -5
- data/test/vagrant/actions/vm/provision_test.rb +3 -3
- data/test/vagrant/actions/vm/reload_test.rb +1 -1
- data/test/vagrant/actions/vm/shared_folders_test.rb +41 -74
- data/test/vagrant/actions/vm/start_test.rb +41 -3
- data/test/vagrant/actions/vm/up_test.rb +10 -21
- data/test/vagrant/active_list_test.rb +28 -43
- data/test/vagrant/commands/base_test.rb +25 -4
- data/test/vagrant/commands/destroy_test.rb +24 -12
- data/test/vagrant/commands/halt_test.rb +33 -11
- data/test/vagrant/commands/package_test.rb +77 -57
- data/test/vagrant/commands/provision_test.rb +50 -0
- data/test/vagrant/commands/reload_test.rb +27 -11
- data/test/vagrant/commands/resume_test.rb +25 -14
- data/test/vagrant/commands/ssh_config_test.rb +40 -17
- data/test/vagrant/commands/ssh_test.rb +52 -13
- data/test/vagrant/commands/status_test.rb +21 -1
- data/test/vagrant/commands/suspend_test.rb +25 -14
- data/test/vagrant/commands/up_test.rb +25 -19
- data/test/vagrant/config_test.rb +74 -18
- data/test/vagrant/downloaders/base_test.rb +2 -1
- data/test/vagrant/downloaders/http_test.rb +18 -8
- data/test/vagrant/environment_test.rb +245 -77
- data/test/vagrant/provisioners/base_test.rb +4 -4
- data/test/vagrant/provisioners/chef_server_test.rb +18 -7
- data/test/vagrant/provisioners/chef_solo_test.rb +17 -7
- data/test/vagrant/provisioners/chef_test.rb +22 -9
- data/test/vagrant/resource_logger_test.rb +144 -0
- data/test/vagrant/ssh_session_test.rb +46 -0
- data/test/vagrant/ssh_test.rb +42 -2
- data/test/vagrant/systems/linux_test.rb +174 -0
- data/test/vagrant/util/error_helper_test.rb +5 -0
- data/test/vagrant/util/output_helper_test.rb +5 -0
- data/test/vagrant/util/plain_logger_test.rb +17 -0
- data/test/vagrant/util/platform_test.rb +18 -0
- data/test/vagrant/util/{errors_test.rb → translator_test.rb} +25 -21
- data/test/vagrant/util_test.rb +12 -49
- data/test/vagrant/vm_test.rb +133 -11
- data/vagrant.gemspec +39 -15
- metadata +38 -14
- data/lib/vagrant/commands/down.rb +0 -16
- data/lib/vagrant/util/errors.rb +0 -36
- data/lib/vagrant/util/progress_meter.rb +0 -33
- data/test/vagrant/commands/down_test.rb +0 -17
- data/test/vagrant/util/progress_meter_test.rb +0 -33
@@ -16,6 +16,7 @@ module Vagrant
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def provision!
|
19
|
+
verify_binary("chef-client")
|
19
20
|
chown_provisioning_folder
|
20
21
|
create_client_key_folder
|
21
22
|
upload_validation_key
|
@@ -28,14 +29,14 @@ module Vagrant
|
|
28
29
|
logger.info "Creating folder to hold client key..."
|
29
30
|
path = Pathname.new(env.config.chef.client_key_path)
|
30
31
|
|
31
|
-
|
32
|
+
vm.ssh.execute do |ssh|
|
32
33
|
ssh.exec!("sudo mkdir -p #{path.dirname}")
|
33
34
|
end
|
34
35
|
end
|
35
36
|
|
36
37
|
def upload_validation_key
|
37
38
|
logger.info "Uploading chef client validation key..."
|
38
|
-
|
39
|
+
vm.ssh.upload!(validation_key_path, guest_validation_key_path)
|
39
40
|
end
|
40
41
|
|
41
42
|
def setup_server_config
|
@@ -49,12 +50,18 @@ module Vagrant
|
|
49
50
|
end
|
50
51
|
|
51
52
|
def run_chef_client
|
53
|
+
command = "cd #{env.config.chef.provisioning_path} && sudo chef-client -c client.rb -j dna.json"
|
54
|
+
|
52
55
|
logger.info "Running chef-client..."
|
53
|
-
|
54
|
-
ssh.exec!(
|
56
|
+
vm.ssh.execute do |ssh|
|
57
|
+
ssh.exec!(command) do |channel, type, data|
|
55
58
|
# TODO: Very verbose. It would be easier to save the data and only show it during
|
56
59
|
# an error, or when verbosity level is set high
|
57
|
-
|
60
|
+
if type == :exit_status
|
61
|
+
ssh.check_exit_status(data, command)
|
62
|
+
else
|
63
|
+
logger.info("#{data}: #{type}")
|
64
|
+
end
|
58
65
|
end
|
59
66
|
end
|
60
67
|
end
|
@@ -64,7 +71,7 @@ module Vagrant
|
|
64
71
|
end
|
65
72
|
|
66
73
|
def guest_validation_key_path
|
67
|
-
File.join(
|
74
|
+
File.join(env.config.chef.provisioning_path, "validation.pem")
|
68
75
|
end
|
69
76
|
end
|
70
77
|
end
|
@@ -8,6 +8,7 @@ module Vagrant
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def provision!
|
11
|
+
verify_binary("chef-solo")
|
11
12
|
chown_provisioning_folder
|
12
13
|
setup_json
|
13
14
|
setup_solo_config
|
@@ -35,12 +36,15 @@ module Vagrant
|
|
35
36
|
end
|
36
37
|
|
37
38
|
def run_chef_solo
|
39
|
+
command = "cd #{env.config.chef.provisioning_path} && sudo chef-solo -c solo.rb -j dna.json"
|
40
|
+
|
38
41
|
logger.info "Running chef-solo..."
|
39
|
-
|
40
|
-
ssh.exec!(
|
42
|
+
vm.ssh.execute do |ssh|
|
43
|
+
ssh.exec!(command) do |channel, type, data|
|
41
44
|
# TODO: Very verbose. It would be easier to save the data and only show it during
|
42
45
|
# an error, or when verbosity level is set high
|
43
|
-
|
46
|
+
ssh.check_exit_status(data, command) if type == :exit_status
|
47
|
+
logger.info("#{data}: #{type}") if type != :exit_status
|
44
48
|
end
|
45
49
|
end
|
46
50
|
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require 'thread'
|
2
|
+
|
3
|
+
module Vagrant
|
4
|
+
# Represents a logger for a specific resource within Vagrant. Each
|
5
|
+
# logger should be initialized and set to represent a single
|
6
|
+
# resource. Each logged message will then appear in the following
|
7
|
+
# format:
|
8
|
+
#
|
9
|
+
# [resource] message
|
10
|
+
#
|
11
|
+
# This class is thread safe. The backing class which actually does
|
12
|
+
# all the logging IO is protected.
|
13
|
+
#
|
14
|
+
# This class also handles progress meters of multiple resources and
|
15
|
+
# handles all the proper interleaving and console updating to
|
16
|
+
# display the progress meters in a way which doesn't conflict with
|
17
|
+
# other incoming log messages.
|
18
|
+
class ResourceLogger
|
19
|
+
@@singleton_logger = nil
|
20
|
+
@@progress_reporters = nil
|
21
|
+
@@writer_lock = Mutex.new
|
22
|
+
|
23
|
+
# The resource which this logger represents.
|
24
|
+
attr_reader :resource
|
25
|
+
|
26
|
+
# The environment that this logger is part of
|
27
|
+
attr_reader :env
|
28
|
+
|
29
|
+
# The backing logger which actually handles the IO. This logger
|
30
|
+
# should be a subclass of the standard library Logger, in general.
|
31
|
+
# IMPORTANT: This logger must be thread-safe.
|
32
|
+
attr_reader :logger
|
33
|
+
|
34
|
+
class << self
|
35
|
+
# Returns a singleton logger. If one has not yet be
|
36
|
+
# instantiated, then the given environment will be used to
|
37
|
+
# create a new logger.
|
38
|
+
def singleton_logger(env=nil)
|
39
|
+
if env && env.config && env.config.loaded?
|
40
|
+
@@singleton_logger ||= Util::PlainLogger.new(env.config.vagrant.log_output)
|
41
|
+
else
|
42
|
+
Util::PlainLogger.new(nil)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Resets the singleton logger (only used for testing).
|
47
|
+
def reset_singleton_logger!
|
48
|
+
@@singleton_logger = nil
|
49
|
+
end
|
50
|
+
|
51
|
+
# Returns the progress parts array which contains the various
|
52
|
+
# progress reporters.
|
53
|
+
def progress_reporters
|
54
|
+
@@progress_reporters ||= {}
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def initialize(resource, env)
|
59
|
+
@resource = resource
|
60
|
+
@env = env
|
61
|
+
@logger = self.class.singleton_logger(env)
|
62
|
+
end
|
63
|
+
|
64
|
+
# TODO: The other logging methods.
|
65
|
+
|
66
|
+
def info(message)
|
67
|
+
@@writer_lock.synchronize do
|
68
|
+
# We clear the line in case progress reports have been going
|
69
|
+
# out.
|
70
|
+
print(cl_reset)
|
71
|
+
logger.info("[#{resource}] #{message}")
|
72
|
+
end
|
73
|
+
|
74
|
+
# Once again flush the progress reporters since we probably
|
75
|
+
# cleared any existing ones.
|
76
|
+
flush_progress
|
77
|
+
end
|
78
|
+
|
79
|
+
# Sets a progress report for the resource that this logger
|
80
|
+
# represents. This progress report is interleaved within the output.
|
81
|
+
def report_progress(progress, total, show_parts=true)
|
82
|
+
# Simply add the progress reporter to the list of progress
|
83
|
+
# reporters
|
84
|
+
self.class.progress_reporters[resource] = {
|
85
|
+
:progress => progress,
|
86
|
+
:total => total,
|
87
|
+
:show_parts => show_parts
|
88
|
+
}
|
89
|
+
|
90
|
+
# And force an update to occur
|
91
|
+
flush_progress
|
92
|
+
end
|
93
|
+
|
94
|
+
# Clears the progress report for this resource
|
95
|
+
def clear_progress
|
96
|
+
self.class.progress_reporters.delete(resource)
|
97
|
+
end
|
98
|
+
|
99
|
+
def flush_progress
|
100
|
+
# Don't do anything if there are no progress reporters
|
101
|
+
return if self.class.progress_reporters.length <= 0
|
102
|
+
|
103
|
+
@@writer_lock.synchronize do
|
104
|
+
reports = []
|
105
|
+
|
106
|
+
# First generate all the report percentages and output
|
107
|
+
self.class.progress_reporters.each do |name, data|
|
108
|
+
percent = (data[:progress].to_f / data[:total].to_f) * 100
|
109
|
+
line = "#{name}: #{percent.to_i}%"
|
110
|
+
line << " (#{data[:progress]} / #{data[:total]})" if data[:show_parts]
|
111
|
+
reports << line
|
112
|
+
end
|
113
|
+
|
114
|
+
# Output it to stdout
|
115
|
+
print "#{cl_reset}[progress] #{reports.join(" ")}"
|
116
|
+
$stdout.flush
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def cl_reset
|
121
|
+
reset = "\r"
|
122
|
+
reset += "\e[0K" unless Mario::Platform.windows?
|
123
|
+
reset
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
data/lib/vagrant/ssh.rb
CHANGED
@@ -48,8 +48,11 @@ module Vagrant
|
|
48
48
|
Net::SSH.start(env.config.ssh.host,
|
49
49
|
env.config[:ssh][:username],
|
50
50
|
opts.merge( :port => port,
|
51
|
-
:keys => [env.config.ssh.private_key_path]
|
52
|
-
|
51
|
+
:keys => [env.config.ssh.private_key_path],
|
52
|
+
:user_known_hosts_file => [],
|
53
|
+
:paranoid => false,
|
54
|
+
:config => false)) do |ssh|
|
55
|
+
yield SSH::Session.new(ssh)
|
53
56
|
end
|
54
57
|
end
|
55
58
|
|
@@ -57,9 +60,16 @@ module Vagrant
|
|
57
60
|
# or StringIO, and `to` is expected to be a path. This method simply forwards
|
58
61
|
# the arguments to `Net::SCP#upload!` so view that for more information.
|
59
62
|
def upload!(from, to)
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
+
tries = 5
|
64
|
+
|
65
|
+
begin
|
66
|
+
execute do |ssh|
|
67
|
+
scp = Net::SCP.new(ssh.session)
|
68
|
+
scp.upload!(from, to)
|
69
|
+
end
|
70
|
+
rescue IOError
|
71
|
+
retry if (tries -= 1) > 0
|
72
|
+
raise
|
63
73
|
end
|
64
74
|
end
|
65
75
|
|
@@ -87,12 +97,14 @@ module Vagrant
|
|
87
97
|
# Checks the file permissions for the private key, resetting them
|
88
98
|
# if needed, or on failure erroring.
|
89
99
|
def check_key_permissions(key_path)
|
100
|
+
return if Mario::Platform.windows?
|
101
|
+
|
90
102
|
# TODO: This only works on unix based systems for now. Windows
|
91
103
|
# systems will need to be investigated further.
|
92
104
|
stat = File.stat(key_path)
|
93
105
|
|
94
106
|
if stat.owned? && file_perms(key_path) != "600"
|
95
|
-
logger.info "Permissions on private key incorrect, fixing..."
|
107
|
+
env.logger.info "Permissions on private key incorrect, fixing..."
|
96
108
|
File.chmod(0600, key_path)
|
97
109
|
|
98
110
|
error_and_exit(:ssh_bad_permissions, :key_path => key_path) if file_perms(key_path) != "600"
|
@@ -112,9 +124,98 @@ module Vagrant
|
|
112
124
|
|
113
125
|
# Returns the port which is either given in the options hash or taken from
|
114
126
|
# the config by finding it in the forwarded ports hash based on the
|
115
|
-
# `config.ssh.forwarded_port_key`
|
127
|
+
# `config.ssh.forwarded_port_key` or use the default port given by `config.ssh.port`
|
128
|
+
# when port forwarding isn't used.
|
116
129
|
def port(opts={})
|
117
|
-
|
130
|
+
# Check if port was specified in options hash
|
131
|
+
pnum = opts[:port]
|
132
|
+
return pnum if pnum
|
133
|
+
|
134
|
+
# Check if we have an SSH forwarded port
|
135
|
+
pnum = env.vm.vm.forwarded_ports.detect do |fp|
|
136
|
+
fp.name == env.config.ssh.forwarded_port_key
|
137
|
+
end
|
138
|
+
|
139
|
+
return pnum.hostport if pnum
|
140
|
+
|
141
|
+
# Fall back to the default
|
142
|
+
return env.config.ssh.port
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
class SSH
|
147
|
+
# A helper class which wraps around `Net::SSH::Connection::Session`
|
148
|
+
# in order to provide basic command error checking while still
|
149
|
+
# providing access to the actual session object.
|
150
|
+
class Session
|
151
|
+
attr_reader :session
|
152
|
+
|
153
|
+
def initialize(session)
|
154
|
+
@session = session
|
155
|
+
end
|
156
|
+
|
157
|
+
# Executes a given command on the SSH session and blocks until
|
158
|
+
# the command completes. This is an almost line for line copy of
|
159
|
+
# the actual `exec!` implementation, except that this
|
160
|
+
# implementation also reports `:exit_status` to the block if given.
|
161
|
+
def exec!(command, options=nil, &block)
|
162
|
+
options = {
|
163
|
+
:error_check => true
|
164
|
+
}.merge(options || {})
|
165
|
+
|
166
|
+
block ||= Proc.new do |ch, type, data|
|
167
|
+
check_exit_status(data, command, options) if type == :exit_status && options[:error_check]
|
168
|
+
|
169
|
+
ch[:result] ||= ""
|
170
|
+
ch[:result] << data if [:stdout, :stderr].include?(type)
|
171
|
+
end
|
172
|
+
|
173
|
+
tries = 5
|
174
|
+
|
175
|
+
begin
|
176
|
+
metach = session.open_channel do |channel|
|
177
|
+
channel.exec(command) do |ch, success|
|
178
|
+
raise "could not execute command: #{command.inspect}" unless success
|
179
|
+
|
180
|
+
# Output stdout data to the block
|
181
|
+
channel.on_data do |ch2, data|
|
182
|
+
block.call(ch2, :stdout, data)
|
183
|
+
end
|
184
|
+
|
185
|
+
# Output stderr data to the block
|
186
|
+
channel.on_extended_data do |ch2, type, data|
|
187
|
+
block.call(ch2, :stderr, data)
|
188
|
+
end
|
189
|
+
|
190
|
+
# Output exit status information to the block
|
191
|
+
channel.on_request("exit-status") do |ch2, data|
|
192
|
+
block.call(ch2, :exit_status, data.read_long)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
rescue IOError
|
197
|
+
retry if (tries -= 1) > 0
|
198
|
+
raise
|
199
|
+
end
|
200
|
+
|
201
|
+
metach.wait
|
202
|
+
metach[:result]
|
203
|
+
end
|
204
|
+
|
205
|
+
# Checks for an erroroneous exit status and raises an exception
|
206
|
+
# if so.
|
207
|
+
def check_exit_status(exit_status, command, options=nil)
|
208
|
+
if exit_status != 0
|
209
|
+
options = {
|
210
|
+
:error_key => :ssh_bad_exit_status,
|
211
|
+
:error_data => {
|
212
|
+
:command => command
|
213
|
+
}
|
214
|
+
}.merge(options || {})
|
215
|
+
|
216
|
+
raise Actions::ActionException.new(options[:error_key], options[:error_data])
|
217
|
+
end
|
218
|
+
end
|
118
219
|
end
|
119
220
|
end
|
120
221
|
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module Vagrant
|
2
|
+
module Systems
|
3
|
+
# The base class for a "system." A system represents an installed
|
4
|
+
# operating system on a given box. There are some portions of
|
5
|
+
# Vagrant which are fairly OS-specific (such as mounting shared
|
6
|
+
# folders) and while the number is few, this abstraction allows
|
7
|
+
# more obscure operating systems to be installed without having
|
8
|
+
# to directly modify Vagrant internals.
|
9
|
+
#
|
10
|
+
# Subclasses of the system base class are expected to implement
|
11
|
+
# all the methods. These methods are described in the comments
|
12
|
+
# above their definition.
|
13
|
+
#
|
14
|
+
# **This is by no means a complete specification. The methods
|
15
|
+
# required by systems can and will change at any time. Any
|
16
|
+
# changes will be noted on release notes.**
|
17
|
+
class Base
|
18
|
+
include Vagrant::Util
|
19
|
+
|
20
|
+
# The VM which this system is tied to.
|
21
|
+
attr_reader :vm
|
22
|
+
|
23
|
+
# Initializes the system. Any subclasses MUST make sure this
|
24
|
+
# method is called on the parent. Therefore, if a subclass overrides
|
25
|
+
# `initialize`, then you must call `super`.
|
26
|
+
def initialize(vm)
|
27
|
+
@vm = vm
|
28
|
+
end
|
29
|
+
|
30
|
+
# A convenience method to access the logger on the VM
|
31
|
+
# environment.
|
32
|
+
def logger
|
33
|
+
vm.env.logger
|
34
|
+
end
|
35
|
+
|
36
|
+
# Halt the machine. This method should gracefully shut down the
|
37
|
+
# operating system. This method will cause `vagrant halt` and associated
|
38
|
+
# commands to _block_, meaning that if the machine doesn't halt
|
39
|
+
# in a reasonable amount of time, this method should just return.
|
40
|
+
#
|
41
|
+
# If when this method returns, the machine's state isn't "powered_off,"
|
42
|
+
# Vagrant will proceed to forcefully shut the machine down.
|
43
|
+
def halt; end
|
44
|
+
|
45
|
+
# Mounts a shared folder. This method is called by the shared
|
46
|
+
# folder action with an open SSH session (passed in as `ssh`).
|
47
|
+
# This method should create, mount, and properly set permissions
|
48
|
+
# on the shared folder. This method should also properly
|
49
|
+
# adhere to any configuration values such as `shared_folder_uid`
|
50
|
+
# on `config.vm`.
|
51
|
+
#
|
52
|
+
# @param [Object] ssh The Net::SSH session.
|
53
|
+
# @param [String] name The name of the shared folder.
|
54
|
+
# @param [String] guestpath The path on the machine which the user
|
55
|
+
# wants the folder mounted.
|
56
|
+
def mount_shared_folder(ssh, name, guestpath); end
|
57
|
+
|
58
|
+
# Prepares the system for host only networks. This is called
|
59
|
+
# once prior to any `enable_host_only_network` calls.
|
60
|
+
def prepare_host_only_network; end
|
61
|
+
|
62
|
+
# Setup the system by adding a new host only network. This
|
63
|
+
# method should configure and bring up the interface for the
|
64
|
+
# given options.
|
65
|
+
#
|
66
|
+
# @param [Hash] net_options The options for the network.
|
67
|
+
def enable_host_only_network(net_options); end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
module Vagrant
|
2
|
+
module Systems
|
3
|
+
# A general Vagrant system implementation for "linux." In general,
|
4
|
+
# any linux-based OS will work fine with this system, although its
|
5
|
+
# not tested exhaustively. BSD or other based systems may work as
|
6
|
+
# well, but that hasn't been tested at all.
|
7
|
+
#
|
8
|
+
# At any rate, this system implementation should server as an
|
9
|
+
# example of how to implement any custom systems necessary.
|
10
|
+
class Linux < Base
|
11
|
+
# A custom config class which will be made accessible via `config.linux`
|
12
|
+
# This is not necessary for all system implementers, of course. However,
|
13
|
+
# generally, Vagrant tries to make almost every aspect of its execution
|
14
|
+
# configurable, and this assists that goal.
|
15
|
+
class LinuxConfig < Vagrant::Config::Base
|
16
|
+
attr_accessor :halt_timeout
|
17
|
+
attr_accessor :halt_check_interval
|
18
|
+
|
19
|
+
def initialize
|
20
|
+
@halt_timeout = 15
|
21
|
+
@halt_check_interval = 1
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Register config class
|
26
|
+
Config.configures :linux, LinuxConfig
|
27
|
+
|
28
|
+
#-------------------------------------------------------------------
|
29
|
+
# Overridden methods
|
30
|
+
#-------------------------------------------------------------------
|
31
|
+
def halt
|
32
|
+
logger.info "Attempting graceful shutdown of linux..."
|
33
|
+
vm.ssh.execute do |ssh|
|
34
|
+
ssh.exec!("sudo halt")
|
35
|
+
end
|
36
|
+
|
37
|
+
# Wait until the VM's state is actually powered off. If this doesn't
|
38
|
+
# occur within a reasonable amount of time (15 seconds by default),
|
39
|
+
# then simply return and allow Vagrant to kill the machine.
|
40
|
+
count = 0
|
41
|
+
while vm.vm.state != :powered_off
|
42
|
+
count += 1
|
43
|
+
|
44
|
+
return if count >= vm.env.config.linux.halt_timeout
|
45
|
+
sleep vm.env.config.linux.halt_check_interval
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def mount_shared_folder(ssh, name, guestpath)
|
50
|
+
ssh.exec!("sudo mkdir -p #{guestpath}")
|
51
|
+
mount_folder(ssh, name, guestpath)
|
52
|
+
chown(ssh, guestpath)
|
53
|
+
end
|
54
|
+
|
55
|
+
def create_sync(ssh, opts)
|
56
|
+
crontab_entry = render_crontab_entry(opts.merge(:syncopts => config.vm.sync_opts,
|
57
|
+
:scriptname => config.vm.sync_script))
|
58
|
+
|
59
|
+
ssh.exec!("sudo mkdir -p #{opts[:syncpath]}")
|
60
|
+
chown(ssh, opts[:syncpath])
|
61
|
+
ssh.exec!("sudo echo \"#{crontab_entry}\" >> #{config.vm.sync_crontab_entry_file}")
|
62
|
+
ssh.exec!("crontab #{config.vm.sync_crontab_entry_file}")
|
63
|
+
end
|
64
|
+
|
65
|
+
def prepare_sync(ssh)
|
66
|
+
logger.info "Preparing system for sync..."
|
67
|
+
vm.ssh.upload!(StringIO.new(render_sync), config.vm.sync_script)
|
68
|
+
ssh.exec!("sudo chmod +x #{config.vm.sync_script}")
|
69
|
+
ssh.exec!("sudo rm #{config.vm.sync_crontab_entry_file}", :error_check => false)
|
70
|
+
end
|
71
|
+
|
72
|
+
def prepare_host_only_network
|
73
|
+
# Remove any previous host only network additions to the
|
74
|
+
# interface file.
|
75
|
+
vm.ssh.execute do |ssh|
|
76
|
+
# Verify debian/ubuntu
|
77
|
+
ssh.exec!("cat /etc/debian_version", :error_key => :network_not_debian)
|
78
|
+
|
79
|
+
# Clear out any previous entries
|
80
|
+
ssh.exec!("sudo sed -e '/^#VAGRANT-BEGIN/,/^#VAGRANT-END/ d' /etc/network/interfaces > /tmp/vagrant-network-interfaces")
|
81
|
+
ssh.exec!("sudo su -c 'cat /tmp/vagrant-network-interfaces > /etc/network/interfaces'")
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def enable_host_only_network(net_options)
|
86
|
+
entry = TemplateRenderer.render('network_entry', :net_options => net_options)
|
87
|
+
vm.ssh.upload!(StringIO.new(entry), "/tmp/vagrant-network-entry")
|
88
|
+
|
89
|
+
vm.ssh.execute do |ssh|
|
90
|
+
ssh.exec!("sudo su -c 'cat /tmp/vagrant-network-entry >> /etc/network/interfaces'")
|
91
|
+
ssh.exec!("sudo /etc/init.d/networking restart")
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
#-------------------------------------------------------------------
|
96
|
+
# "Private" methods which assist above methods
|
97
|
+
#-------------------------------------------------------------------
|
98
|
+
def mount_folder(ssh, name, guestpath, sleeptime=5)
|
99
|
+
# Determine the permission string to attach to the mount command
|
100
|
+
perms = []
|
101
|
+
perms << "uid=#{vm.env.config.vm.shared_folder_uid}"
|
102
|
+
perms << "gid=#{vm.env.config.vm.shared_folder_gid}"
|
103
|
+
perms = " -o #{perms.join(",")}" if !perms.empty?
|
104
|
+
|
105
|
+
attempts = 0
|
106
|
+
while true
|
107
|
+
result = ssh.exec!("sudo mount -t vboxsf#{perms} #{name} #{guestpath}") do |ch, type, data|
|
108
|
+
# net/ssh returns the value in ch[:result] (based on looking at source)
|
109
|
+
ch[:result] = !!(type == :stderr && data =~ /No such device/i)
|
110
|
+
end
|
111
|
+
|
112
|
+
break unless result
|
113
|
+
|
114
|
+
attempts += 1
|
115
|
+
raise Actions::ActionException.new(:vm_mount_fail) if attempts >= 10
|
116
|
+
sleep sleeptime
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def chown(ssh, dir)
|
121
|
+
ssh.exec!("sudo chown #{config.ssh.username} #{dir}")
|
122
|
+
end
|
123
|
+
|
124
|
+
def config
|
125
|
+
vm.env.config
|
126
|
+
end
|
127
|
+
|
128
|
+
def render_sync
|
129
|
+
TemplateRenderer.render('sync')
|
130
|
+
end
|
131
|
+
|
132
|
+
def render_crontab_entry(opts)
|
133
|
+
TemplateRenderer.render('crontab_entry', opts)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|