vmit 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/MIT-LICENSE +22 -0
- data/README.rdoc +119 -0
- data/Rakefile +1 -0
- data/bin/vmit +145 -0
- data/bin/vmit-ifdown +10 -0
- data/bin/vmit-ifup +18 -0
- data/lib/vmit.rb +67 -0
- data/lib/vmit/autoyast.rb +110 -0
- data/lib/vmit/bootstrap.rb +273 -0
- data/lib/vmit/debian_preseed.rb +64 -0
- data/lib/vmit/ext.rb +38 -0
- data/lib/vmit/kickstart.rb +67 -0
- data/lib/vmit/logger.rb +66 -0
- data/lib/vmit/network.rb +161 -0
- data/lib/vmit/plugins/bootstrap.rb +82 -0
- data/lib/vmit/plugins/hello.rb +33 -0
- data/lib/vmit/refcounted_resource.rb +134 -0
- data/lib/vmit/utils.rb +103 -0
- data/lib/vmit/version.rb +23 -0
- data/lib/vmit/vfs.rb +210 -0
- data/lib/vmit/virtual_machine.rb +299 -0
- data/test/bootstrap_test.rb +50 -0
- data/test/data/dir1/file.txt +2 -0
- data/test/data/test_vfs.iso +0 -0
- data/test/helper.rb +28 -0
- data/test/refcounted_resource_test.rb +35 -0
- data/test/vfs_test.rb +85 -0
- data/vmit.gemspec +31 -0
- metadata +244 -0
data/lib/vmit/version.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (C) 2013 Duncan Mac-Vicar P. <dmacvicar@suse.de>
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
5
|
+
# this software and associated documentation files (the "Software"), to deal in
|
6
|
+
# the Software without restriction, including without limitation the rights to
|
7
|
+
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
8
|
+
# the Software, and to permit persons to whom the Software is furnished to do so,
|
9
|
+
# subject to the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be included in all
|
12
|
+
# copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
16
|
+
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
17
|
+
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
18
|
+
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
19
|
+
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
20
|
+
#
|
21
|
+
module Vmit
|
22
|
+
VERSION = "0.0.3"
|
23
|
+
end
|
data/lib/vmit/vfs.rb
ADDED
@@ -0,0 +1,210 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (C) 2013 Duncan Mac-Vicar P. <dmacvicar@suse.de>
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
5
|
+
# this software and associated documentation files (the "Software"), to deal in
|
6
|
+
# the Software without restriction, including without limitation the rights to
|
7
|
+
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
8
|
+
# the Software, and to permit persons to whom the Software is furnished to do so,
|
9
|
+
# subject to the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be included in all
|
12
|
+
# copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
16
|
+
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
17
|
+
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
18
|
+
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
19
|
+
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
20
|
+
#
|
21
|
+
require 'abstract_method'
|
22
|
+
require 'cheetah'
|
23
|
+
require 'uri'
|
24
|
+
require 'open-uri'
|
25
|
+
require 'progressbar'
|
26
|
+
require 'tempfile'
|
27
|
+
|
28
|
+
module Vmit
|
29
|
+
|
30
|
+
module VFS
|
31
|
+
|
32
|
+
# Opens a location
|
33
|
+
def self.from(location, *rest, &block)
|
34
|
+
[ISO, URI, Local].each do |handler|
|
35
|
+
if handler.accept?(location)
|
36
|
+
return handler.from(location)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
raise ArgumentError.new("#{location} not supported")
|
40
|
+
end
|
41
|
+
|
42
|
+
class Handler
|
43
|
+
# alias for new
|
44
|
+
def self.from(*args)
|
45
|
+
self.new(*args)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class URI < Handler
|
50
|
+
|
51
|
+
# Whether this handler accepts the
|
52
|
+
# given location
|
53
|
+
#
|
54
|
+
# @param uri [URI,String] location
|
55
|
+
def self.accept?(location)
|
56
|
+
uri = case location
|
57
|
+
when ::URI then location
|
58
|
+
else ::URI.parse(location.to_s)
|
59
|
+
end
|
60
|
+
['http', 'ftp'].include?(uri.scheme)
|
61
|
+
end
|
62
|
+
|
63
|
+
# @param [String] base_url Base location
|
64
|
+
def initialize(location)
|
65
|
+
@base_uri = case location
|
66
|
+
when ::URI then location
|
67
|
+
else ::URI.parse(location.to_s)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.open(loc, *rest, &block)
|
72
|
+
uri = case loc
|
73
|
+
when ::URI then loc
|
74
|
+
else ::URI.parse(loc.to_s)
|
75
|
+
end
|
76
|
+
unless accept?(uri)
|
77
|
+
raise ArgumentError.new('Only HTTP/FTP supported')
|
78
|
+
end
|
79
|
+
@pbar = nil
|
80
|
+
@filename = File.basename(uri.path)
|
81
|
+
ret = OpenURI.open_uri(uri.to_s,
|
82
|
+
:content_length_proc => lambda { |t|
|
83
|
+
if t && 0 < t
|
84
|
+
@pbar = ProgressBar.new(@filename, t)
|
85
|
+
@pbar.file_transfer_mode
|
86
|
+
end
|
87
|
+
},
|
88
|
+
:progress_proc => lambda { |s|
|
89
|
+
@pbar.set s if @pbar
|
90
|
+
}, &block)
|
91
|
+
@pbar = nil
|
92
|
+
# So that the progress bar line get overwriten
|
93
|
+
STDOUT.print "\r"
|
94
|
+
STDOUT.flush
|
95
|
+
ret
|
96
|
+
end
|
97
|
+
# Open a filename relative to the
|
98
|
+
# base location.
|
99
|
+
#
|
100
|
+
# @param [String] loc Location to open.
|
101
|
+
# If a base URI was given for HTTP then
|
102
|
+
# the path will be relative to that
|
103
|
+
def open(loc, *rest, &block)
|
104
|
+
uri = @base_uri.clone
|
105
|
+
uri.path = File.join(uri.path, loc.to_s)
|
106
|
+
|
107
|
+
Vmit::VFS::URI.open(uri, *rest, &block)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
class ISO < Handler
|
112
|
+
|
113
|
+
attr_reader :iso_file
|
114
|
+
|
115
|
+
# Whether this handler accepts the
|
116
|
+
# given location.
|
117
|
+
#
|
118
|
+
# @param uri [URI,String] location
|
119
|
+
def self.accept?(location)
|
120
|
+
uri = case location
|
121
|
+
when ::URI then location
|
122
|
+
else ::URI.parse(location)
|
123
|
+
end
|
124
|
+
|
125
|
+
# either an iso:// url or a local file
|
126
|
+
unless (uri.scheme == 'iso' || uri.scheme.nil?)
|
127
|
+
return false
|
128
|
+
end
|
129
|
+
return false unless File.exist?(uri.path)
|
130
|
+
File.open(uri.path) do |f|
|
131
|
+
f.seek(0x8001)
|
132
|
+
return true if f.read(5) == 'CD001'
|
133
|
+
end
|
134
|
+
false
|
135
|
+
end
|
136
|
+
|
137
|
+
# Creates a ISO handler for +iso+
|
138
|
+
# @param [URI, String] iso ISO file
|
139
|
+
def initialize(location, *rest)
|
140
|
+
raise ArgumentError.new(location) unless self.class.accept?(location)
|
141
|
+
path = case location
|
142
|
+
when ::URI then location.path
|
143
|
+
else ::URI.parse(location).path
|
144
|
+
end
|
145
|
+
@iso_file = path
|
146
|
+
end
|
147
|
+
|
148
|
+
# Takes a iso URI on the form
|
149
|
+
# iso:///path/tothe/file.iso?path=/file/to/get
|
150
|
+
#
|
151
|
+
# @param [URI, String] uri ISO file and path as query string
|
152
|
+
def self.open(location)
|
153
|
+
uri = case location
|
154
|
+
when ::URI then location
|
155
|
+
else ::URI.parse(location)
|
156
|
+
end
|
157
|
+
handler = self.new(uri)
|
158
|
+
query = Hash[*uri.query.split('&').map {|p| p.split('=')}.flatten]
|
159
|
+
unless query.has_key?("path")
|
160
|
+
raise ArgumentError.new("#{uri}: missing path in query string")
|
161
|
+
end
|
162
|
+
handler.open(query["path"])
|
163
|
+
end
|
164
|
+
|
165
|
+
# Takes a path relative to +iso_file+
|
166
|
+
# @see iso_file
|
167
|
+
def open(name, *rest)
|
168
|
+
index = Cheetah.run('isoinfo', '-f', '-R', '-i', iso_file, :stdout => :capture)
|
169
|
+
files = index.each_line.to_a.map(&:strip)
|
170
|
+
raise Errno::ENOENT.new(name) if not files.include?(name)
|
171
|
+
tmp = Tempfile.new('vmit-vfs-iso-')
|
172
|
+
Cheetah.run('isoinfo', '-R', '-i', iso_file, '-x', name, :stdout => tmp)
|
173
|
+
tmp.close
|
174
|
+
tmp.open
|
175
|
+
if block_given?
|
176
|
+
yield tmp
|
177
|
+
end
|
178
|
+
tmp
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
class Local < Handler
|
183
|
+
|
184
|
+
# Whether this handler accepts the
|
185
|
+
# given location
|
186
|
+
#
|
187
|
+
# @param uri [URI,String] location
|
188
|
+
def self.accept?(location)
|
189
|
+
File.directory?(location.to_s)
|
190
|
+
end
|
191
|
+
|
192
|
+
def initialize(base_path=nil)
|
193
|
+
@base_path = base_path
|
194
|
+
@base_path ||= '/'
|
195
|
+
unless File.exist?(@base_path)
|
196
|
+
raise Errno::ENOENT.new(@base_path)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
def self.open(dir, *rest, &block)
|
201
|
+
self.new(dir).open(name, *rest, &block)
|
202
|
+
end
|
203
|
+
|
204
|
+
def open(name, *rest, &block)
|
205
|
+
Kernel.open(File.join(@base_path, name), *rest, &block)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
end
|
210
|
+
end
|
@@ -0,0 +1,299 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (C) 2013 Duncan Mac-Vicar P. <dmacvicar@suse.de>
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
5
|
+
# this software and associated documentation files (the "Software"), to deal in
|
6
|
+
# the Software without restriction, including without limitation the rights to
|
7
|
+
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
8
|
+
# the Software, and to permit persons to whom the Software is furnished to do so,
|
9
|
+
# subject to the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be included in all
|
12
|
+
# copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
16
|
+
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
17
|
+
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
18
|
+
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
19
|
+
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
20
|
+
#
|
21
|
+
require 'cheetah'
|
22
|
+
require 'drb'
|
23
|
+
require 'fileutils'
|
24
|
+
require 'stringio'
|
25
|
+
require 'yaml'
|
26
|
+
|
27
|
+
require 'vmit/utils'
|
28
|
+
|
29
|
+
module Vmit
|
30
|
+
|
31
|
+
class VirtualMachine
|
32
|
+
|
33
|
+
attr_accessor :work_dir
|
34
|
+
|
35
|
+
VM_DEFAULTS = {
|
36
|
+
:memory => '1G',
|
37
|
+
}
|
38
|
+
SWITCH = 'br0'
|
39
|
+
|
40
|
+
# Accessor to current options
|
41
|
+
def [](key)
|
42
|
+
@opts[key]
|
43
|
+
end
|
44
|
+
|
45
|
+
def config_file
|
46
|
+
File.join(work_dir, 'config.yml')
|
47
|
+
end
|
48
|
+
|
49
|
+
def initialize(work_dir)
|
50
|
+
@pidfile = PidFile.new(:piddir => work_dir, :pidfile => "vmit.pid")
|
51
|
+
@work_dir = work_dir
|
52
|
+
|
53
|
+
@opts = {}
|
54
|
+
@opts.merge!(VM_DEFAULTS)
|
55
|
+
|
56
|
+
if File.exist?(config_file)
|
57
|
+
@opts.merge!(YAML::load(File.open(config_file)))
|
58
|
+
end
|
59
|
+
|
60
|
+
# By default the following keys are useful to be
|
61
|
+
# generated if they don't exist and then use the
|
62
|
+
# same in the future UNLESS they are
|
63
|
+
# overriden with vmit run
|
64
|
+
if not @opts.has_key?(:mac_address)
|
65
|
+
@opts[:mac_address] = Vmit::Utils.random_mac_address
|
66
|
+
end
|
67
|
+
|
68
|
+
if not @opts.has_key?(:uuid)
|
69
|
+
@opts[:uuid] = File.read("/proc/sys/kernel/random/uuid").strip
|
70
|
+
end
|
71
|
+
|
72
|
+
@network = if @opts.has_key?(:network)
|
73
|
+
Network.create(@opts[:network])
|
74
|
+
else
|
75
|
+
Vmit.logger.info 'No network selected. Using default.'
|
76
|
+
Network.default
|
77
|
+
end
|
78
|
+
Vmit.logger.info "Network: #{@network}"
|
79
|
+
end
|
80
|
+
|
81
|
+
# @return [Array,<String>] sorted list of snapshots
|
82
|
+
def disk_images
|
83
|
+
Dir.glob(File.join(work_dir, '*.qcow2')).sort do |a,b|
|
84
|
+
File.ctime(a) <=> File.ctime(b)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Takes a disk snapshot
|
89
|
+
def disk_snapshot!
|
90
|
+
disk_image_shift!
|
91
|
+
end
|
92
|
+
|
93
|
+
def disk_image_init!(opts={})
|
94
|
+
disk_image_shift!(opts)
|
95
|
+
end
|
96
|
+
|
97
|
+
DISK_INIT_DEFAULTS = {:disk_size => '10G'}
|
98
|
+
|
99
|
+
# Shifts an image, adding a new one using the
|
100
|
+
# previous newest one as backing file
|
101
|
+
#
|
102
|
+
# @param [Hash] opts options for the disk shift
|
103
|
+
# @option opts [String] :disk_size Disk size. Only used for image creation
|
104
|
+
def disk_image_shift!(opts={})
|
105
|
+
runtime_opts = DISK_INIT_DEFAULTS.merge(opts)
|
106
|
+
|
107
|
+
file_name = File.join(work_dir, "sda-#{Time.now.to_i}.qcow2")
|
108
|
+
images = disk_images
|
109
|
+
|
110
|
+
file_name = 'base.qcow2' if images.size == 0
|
111
|
+
|
112
|
+
args = ['/usr/bin/qemu-img', 'create',
|
113
|
+
'-f', "qcow2"]
|
114
|
+
|
115
|
+
if not images.empty?
|
116
|
+
args << '-b'
|
117
|
+
args << images.last
|
118
|
+
end
|
119
|
+
args << file_name
|
120
|
+
if images.empty?
|
121
|
+
args << runtime_opts[:disk_size]
|
122
|
+
end
|
123
|
+
|
124
|
+
Vmit.logger.info "Shifted image. Current is '#{file_name}'."
|
125
|
+
Cheetah.run(*args)
|
126
|
+
end
|
127
|
+
|
128
|
+
# Rolls back to the previous snapshot
|
129
|
+
def disk_rollback!
|
130
|
+
images = disk_images
|
131
|
+
|
132
|
+
return if images.empty?
|
133
|
+
|
134
|
+
if images.size == 1
|
135
|
+
Vmit.logger.fatal "Only the base snapshot left!"
|
136
|
+
return
|
137
|
+
end
|
138
|
+
Vmit.logger.info "Removing #{images.last}"
|
139
|
+
FileUtils.rm(images.last)
|
140
|
+
end
|
141
|
+
|
142
|
+
# @returns [String] The latest COW snapshot
|
143
|
+
def current_image
|
144
|
+
curr = disk_images.last
|
145
|
+
raise "No hard disk image available" if curr.nil?
|
146
|
+
curr
|
147
|
+
end
|
148
|
+
|
149
|
+
def options
|
150
|
+
@opts
|
151
|
+
end
|
152
|
+
|
153
|
+
# @return [Hash] Config of the virtual machine
|
154
|
+
# This is all options plus the defaults
|
155
|
+
def config
|
156
|
+
VM_DEFAULTS.merge(@opts)
|
157
|
+
end
|
158
|
+
|
159
|
+
# @return [Hash] config that differs from default
|
160
|
+
# and therefore relevant to be persisted in config.yml
|
161
|
+
def relevant_config
|
162
|
+
config.diff(VM_DEFAULTS)
|
163
|
+
end
|
164
|
+
|
165
|
+
# Saves the configuration in config.yml
|
166
|
+
def save_config!
|
167
|
+
if not relevant_config.empty?
|
168
|
+
Vmit.logger.info "Writing config.yml..."
|
169
|
+
File.open(config_file, 'w') do |f|
|
170
|
+
f.write(relevant_config.to_yaml)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def to_s
|
176
|
+
config.to_s
|
177
|
+
end
|
178
|
+
|
179
|
+
BINDIR = File.join(File.dirname(__FILE__), '../../bin')
|
180
|
+
|
181
|
+
# Starts the virtual machine
|
182
|
+
#
|
183
|
+
# @param [Hash] runtime_opts Runtime options
|
184
|
+
# @option runtime_opts [String] :cdrom CDROM image
|
185
|
+
# @option runtime_opts [String] :kernel Kernel image
|
186
|
+
# @option runtime_opts [String] :initrd initrd image
|
187
|
+
# @option runtime_opts [String] :append Kernel command line
|
188
|
+
# @option runtime_opts [String] :floppy Floppy (image or directory)
|
189
|
+
def run(runtime_opts)
|
190
|
+
Vmit.logger.info "Starting VM..."
|
191
|
+
# Don't overwrite @opts so that
|
192
|
+
# run can be called various times
|
193
|
+
opts = {}
|
194
|
+
opts.merge!(@opts)
|
195
|
+
opts.merge!(runtime_opts)
|
196
|
+
|
197
|
+
config.each do |k,v|
|
198
|
+
Vmit.logger.info " => #{k} : #{v}"
|
199
|
+
end
|
200
|
+
|
201
|
+
begin
|
202
|
+
# HACK, will be replaced by a better config system
|
203
|
+
use_virtio = ! File.exist?(File.join(work_dir, '.disable-virtio'))
|
204
|
+
|
205
|
+
ifup = File.expand_path(File.join(BINDIR, 'vmit-ifup'))
|
206
|
+
ifdown = File.expand_path(File.join(BINDIR, 'vmit-ifdown'))
|
207
|
+
|
208
|
+
args = ['/usr/bin/qemu-kvm', '-boot', 'c',
|
209
|
+
'-m', "#{opts[:memory]}",
|
210
|
+
'-pidfile', File.join(work_dir, 'qemu.pid')]
|
211
|
+
|
212
|
+
if use_virtio
|
213
|
+
args << '-drive'
|
214
|
+
args << "file=#{current_image},if=virtio"
|
215
|
+
|
216
|
+
args << '-netdev'
|
217
|
+
args << "type=tap,script=#{ifup},downscript=#{ifdown},id=vnet0"
|
218
|
+
args << '-device'
|
219
|
+
args << "virtio-net-pci,netdev=vnet0,mac=#{opts[:mac_address]}"
|
220
|
+
else
|
221
|
+
args << '-drive'
|
222
|
+
args << "file=#{current_image}"
|
223
|
+
|
224
|
+
args << '-net'
|
225
|
+
args << "nic,macaddr=#{opts[:mac_address]}"
|
226
|
+
args << '-net'
|
227
|
+
args << "tap,script=#{ifup},downscript=#{ifdown}"
|
228
|
+
end
|
229
|
+
|
230
|
+
# advanced options, mostly to be used by plugins
|
231
|
+
[:cdrom, :kernel, :initrd, :append].each do |key|
|
232
|
+
if opts.has_key?(key)
|
233
|
+
args << "-#{key}"
|
234
|
+
args << case opts[key]
|
235
|
+
# append is multple
|
236
|
+
when Array then opts[key].join(' ')
|
237
|
+
else opts[key]
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
if opts.has_key?(:floppy)
|
243
|
+
if File.directory?(opts[:floppy])
|
244
|
+
args << '-fda'
|
245
|
+
args << "fat:floppy:#{opts[:floppy]}"
|
246
|
+
else
|
247
|
+
Vmit.logger.warn "#{opts[:floppy]} : only directories supported"
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
# options that translate to
|
252
|
+
# -no-something if :something => false
|
253
|
+
[:reboot].each do |key|
|
254
|
+
if opts.has_key?(key)
|
255
|
+
# default is true
|
256
|
+
args << "-no-#{key}" if not opts[key]
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
unless ENV['DISABLE_UUID']
|
261
|
+
args << '-uuid'
|
262
|
+
args << "#{opts[:uuid]}"
|
263
|
+
end
|
264
|
+
|
265
|
+
DRb.start_service nil, self
|
266
|
+
ENV['VMIT_SERVER'] = DRb.uri
|
267
|
+
|
268
|
+
ENV['VMIT_SWITCH'] = SWITCH
|
269
|
+
Vmit.logger.debug "Vmit server listening at #{DRb.uri}"
|
270
|
+
|
271
|
+
@network.auto do
|
272
|
+
begin
|
273
|
+
Cheetah.run(*args)
|
274
|
+
ensure
|
275
|
+
FileUtils.rm_f File.join(work_dir, 'qemu.pid')
|
276
|
+
end
|
277
|
+
end
|
278
|
+
rescue PidFile::DuplicateProcessError => e
|
279
|
+
Vmit.logger.fatal "VM in '#{work_dir}'' is already running (#{e})"
|
280
|
+
raise
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
# Called by vmit-ifup
|
285
|
+
def ifup(device)
|
286
|
+
Vmit.logger.info " Bringing interface #{device} up"
|
287
|
+
Cheetah.run '/sbin/ifconfig', device, '0.0.0.0', 'up'
|
288
|
+
@network.connect_interface(device)
|
289
|
+
end
|
290
|
+
|
291
|
+
# Called by vmit-ifdown
|
292
|
+
def ifdown(device)
|
293
|
+
Vmit.logger.info " Bringing down interface #{device}"
|
294
|
+
Cheetah.run '/sbin/ifconfig', device, '0.0.0.0', 'down'
|
295
|
+
@network.disconnect_interface(device)
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
end
|