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