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/network.rb
ADDED
@@ -0,0 +1,161 @@
|
|
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 'ipaddress'
|
24
|
+
require 'yaml'
|
25
|
+
|
26
|
+
require 'vmit/refcounted_resource'
|
27
|
+
|
28
|
+
module Vmit
|
29
|
+
|
30
|
+
class Network < RefcountedResource
|
31
|
+
|
32
|
+
abstract_method :connect_interface
|
33
|
+
abstract_method :disconnect_interface
|
34
|
+
|
35
|
+
def resource_class
|
36
|
+
'network'
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.create(config)
|
40
|
+
case config
|
41
|
+
when Hash then from_config(config)
|
42
|
+
when String then from_alias(config)
|
43
|
+
else raise "Can't build network from #{config}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.from_alias(name)
|
48
|
+
File.open(File.join(ENV['HOME'], '.vmit', 'networks.yml')) do |f|
|
49
|
+
# transform keys into Symbols
|
50
|
+
networks = YAML::load(f)
|
51
|
+
if networks.has_key?(name)
|
52
|
+
return from_config(networks[name].symbolize_keys)
|
53
|
+
else
|
54
|
+
raise "Unknown network #{name}"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.from_config(config)
|
60
|
+
BridgedNetwork.new(config[:address])
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.default
|
64
|
+
BridgedNetwork.new(BridgedNetwork::DEFAULT_NETWORK)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Implementation of networking with a bridge with optional
|
69
|
+
# NAT to the host interface.
|
70
|
+
#
|
71
|
+
class BridgedNetwork < Network
|
72
|
+
|
73
|
+
DEFAULT_NETWORK = '192.168.58.254/24'
|
74
|
+
|
75
|
+
def initialize(address)
|
76
|
+
@address = IPAddress(address).network
|
77
|
+
brdevice = 'br0'
|
78
|
+
@brdevice = brdevice
|
79
|
+
super("#{@brdevice}-#{@address.to_u32}")
|
80
|
+
end
|
81
|
+
|
82
|
+
def to_s
|
83
|
+
"#{@brdevice}:#{@address.to_string}"
|
84
|
+
end
|
85
|
+
|
86
|
+
# reimplemented from RefcountedResource
|
87
|
+
def on_up
|
88
|
+
Vmit.logger.info "Bringing up bridged network #{@address.to_string} on #{@brdevice}"
|
89
|
+
Vmit.logger.info " `-> managed by #{lockfile_path}"
|
90
|
+
# setup bridge
|
91
|
+
# may be use 'ip', 'link', 'show', 'dev', devname to check if
|
92
|
+
# the bridge is there?
|
93
|
+
Cheetah.run '/sbin/brctl', 'addbr', @brdevice
|
94
|
+
File.write("/proc/sys/net/ipv6/conf/#{@brdevice}/disable_ipv6", 1)
|
95
|
+
File.write('/proc/sys/net/ipv4/ip_forward', 1)
|
96
|
+
Cheetah.run '/sbin/brctl', 'stp', @brdevice, 'on'
|
97
|
+
#Cheetah.run '/sbin/brctl', 'setfd', @brdevice, '0' rescue nil
|
98
|
+
# setup network and dhcp on bridge
|
99
|
+
Cheetah.run '/sbin/ifconfig', @brdevice, @address.network.hosts[0].to_s
|
100
|
+
Cheetah.run '/sbin/ifconfig', @brdevice, 'up'
|
101
|
+
Cheetah.run 'iptables', '-t', 'nat', '-A', 'POSTROUTING', '-s', @address.network.to_string,
|
102
|
+
'!', '-d', @address.network.to_string, '-j', 'MASQUERADE'
|
103
|
+
|
104
|
+
start_dnsmasq
|
105
|
+
end
|
106
|
+
|
107
|
+
def connect_interface(device)
|
108
|
+
Vmit.logger.info " Connecting #{device} --> #{@brdevice}"
|
109
|
+
#Vmit::Utils.run_command(*['ovs-vsctl', 'add-port', SWITCH, ARGV[0]])
|
110
|
+
Cheetah.run '/sbin/brctl', 'addif', @brdevice, device
|
111
|
+
end
|
112
|
+
|
113
|
+
# reimplemented from RefcountedResource
|
114
|
+
def on_down
|
115
|
+
Vmit.logger.info "Bringing down bridged network #{@address.to_string} on #{@brdevice}"
|
116
|
+
Vmit.logger.info " `-> managed by #{lockfile_path}"
|
117
|
+
Cheetah.run '/sbin/ifconfig', @brdevice, 'down'
|
118
|
+
Cheetah.run '/sbin/brctl', 'delbr', @brdevice
|
119
|
+
Cheetah.run 'iptables', '-t', 'nat', '-D', 'POSTROUTING', '-s', @address.network.to_string,
|
120
|
+
'!', '-d', @address.network.to_string, '-j', 'MASQUERADE'
|
121
|
+
kill_dnsmasq
|
122
|
+
end
|
123
|
+
|
124
|
+
# reimplemented from RefcountedResource
|
125
|
+
def disconnect_interface(device)
|
126
|
+
Vmit.logger.info " Disconnecting #{device} -X-> #{@brdevice}"
|
127
|
+
#Vmit::Utils.run_command(*['ovs-vsctl', 'del-port', SWITCH, ARGV[0]])
|
128
|
+
Cheetah.run '/sbin/brctl', 'delif', @brdevice, device
|
129
|
+
end
|
130
|
+
|
131
|
+
# reimplemented from RefcountedResource
|
132
|
+
def on_acquire
|
133
|
+
end
|
134
|
+
|
135
|
+
# reimplemented from RefcountedResource
|
136
|
+
def on_release
|
137
|
+
end
|
138
|
+
|
139
|
+
def start_dnsmasq
|
140
|
+
dnsmasq_args = %W(dnsmasq -Z -x #{dnsmasq_pidfile} --strict-order --bind-interfaces --listen-address #{@address.network.hosts[0]} --dhcp-range #{@address.network.hosts[1]},#{@address.network.hosts.last})
|
141
|
+
Vmit.logger.debug "dnsmasq arguments: '#{dnsmasq_args.join(' ')}'"
|
142
|
+
IO.popen(dnsmasq_args)
|
143
|
+
#Vmit.logger.info " dnsmasq spawned with pid #{dnsmasq_pid}"
|
144
|
+
end
|
145
|
+
|
146
|
+
def kill_dnsmasq
|
147
|
+
Vmit.logger.info "Killing dnsmasq (#{dnsmasq_pid})"
|
148
|
+
Process.kill('SIGTERM', dnsmasq_pid)
|
149
|
+
end
|
150
|
+
|
151
|
+
def dnsmasq_pid
|
152
|
+
File.read(dnsmasq_pidfile).strip.to_i
|
153
|
+
end
|
154
|
+
|
155
|
+
def dnsmasq_pidfile
|
156
|
+
File.join(lockfile_dir, 'dnsmasq.pid')
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
|
161
|
+
end
|
@@ -0,0 +1,82 @@
|
|
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 'vmit/autoyast'
|
22
|
+
require 'vmit/kickstart'
|
23
|
+
require 'abstract_method'
|
24
|
+
require 'clamp'
|
25
|
+
require 'net/http'
|
26
|
+
require 'tmpdir'
|
27
|
+
require 'uri'
|
28
|
+
require 'vmit'
|
29
|
+
|
30
|
+
module Vmit
|
31
|
+
module Plugins
|
32
|
+
|
33
|
+
# Bootstrap allows to initialize a virtual machine
|
34
|
+
# from (currently) a (SUSE) repository.
|
35
|
+
#
|
36
|
+
# It will perform an autoinstallation based on
|
37
|
+
# the repository.
|
38
|
+
#
|
39
|
+
class Bootstrap < ::Clamp::Command
|
40
|
+
|
41
|
+
option ["-s","--disk-size"], "SIZE",
|
42
|
+
"Initialize disk with SIZE (eg: 10M, 10G, 10K)" do |disk_size|
|
43
|
+
if not disk_size =~ /(\d)+(M|K|G)/
|
44
|
+
raise ArgumentError, "Disk size should be given as 1M, 2G, etc"
|
45
|
+
end
|
46
|
+
disk_size
|
47
|
+
end
|
48
|
+
|
49
|
+
parameter "LOCATION", "Repository URL or ISO image to bootstrap from"
|
50
|
+
|
51
|
+
def execute
|
52
|
+
Vmit.logger.info 'Starting bootstrap'
|
53
|
+
curr_dir = File.expand_path(Dir.pwd)
|
54
|
+
vm = Vmit::VirtualMachine.new(curr_dir)
|
55
|
+
|
56
|
+
Vmit.logger.info ' Deleting old images'
|
57
|
+
FileUtils.rm_f(Dir.glob('*.qcow2'))
|
58
|
+
opts = {}
|
59
|
+
opts[:disk_size] = disk_size if disk_size
|
60
|
+
vm.disk_image_init!(opts)
|
61
|
+
vm.save_config!
|
62
|
+
|
63
|
+
uri = URI.parse(location)
|
64
|
+
bootstrap = [Vmit::Bootstrap::FromImage,
|
65
|
+
Vmit::Bootstrap::FromMedia].find do |method|
|
66
|
+
method.accept?(uri)
|
67
|
+
end
|
68
|
+
|
69
|
+
if bootstrap
|
70
|
+
bootstrap.new(vm, uri).execute
|
71
|
+
else
|
72
|
+
raise "Can't bootstrap from #{location}"
|
73
|
+
end
|
74
|
+
|
75
|
+
Vmit.logger.info 'Creating snapshot of fresh system.'
|
76
|
+
vm.disk_snapshot!
|
77
|
+
Vmit.logger.info 'Bootstraping done. Call vmit run to start your system.'
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,33 @@
|
|
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 'clamp'
|
22
|
+
|
23
|
+
module Vmit
|
24
|
+
module Plugins
|
25
|
+
class Hello < ::Clamp::Command
|
26
|
+
|
27
|
+
def execute
|
28
|
+
puts "Hello"
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,134 @@
|
|
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 'tmpdir'
|
23
|
+
|
24
|
+
module Vmit
|
25
|
+
|
26
|
+
# This class allows to bring a resource represented
|
27
|
+
# by a shared lock file only once by the
|
28
|
+
# the first process using it, and down when the
|
29
|
+
# last process finishes.
|
30
|
+
#
|
31
|
+
# Think of it as the first one that enters the room
|
32
|
+
# turn the lights on, and the last one that exits,
|
33
|
+
# turns the lights off.
|
34
|
+
#
|
35
|
+
# Call:
|
36
|
+
#
|
37
|
+
# on_up : will bring the resource up if needed
|
38
|
+
# on_down: will bring tthe resource down if no more users
|
39
|
+
# on_acquire: will start using the resource
|
40
|
+
# on_release: will stop using the resource
|
41
|
+
#
|
42
|
+
# Then use the class like this:
|
43
|
+
#
|
44
|
+
# YourRefCountedResource.auto('name') do
|
45
|
+
# # do something
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
class RefcountedResource
|
49
|
+
|
50
|
+
attr_reader :name
|
51
|
+
attr_reader :lockfile_path
|
52
|
+
attr_reader :lockfile_dir
|
53
|
+
|
54
|
+
# The resource class. Resources with the
|
55
|
+
# same class and name are considered to be
|
56
|
+
# the same resource by the locking and refcounting
|
57
|
+
# mechanism.
|
58
|
+
#
|
59
|
+
# For example, you may subclass RefcountedResource as
|
60
|
+
# Network, and then have multiple Network subclasses, but
|
61
|
+
# you can reimplement resource_class once in Network so that
|
62
|
+
# all Network subclasses have the same resource class.
|
63
|
+
#
|
64
|
+
def resource_class
|
65
|
+
(self.class.name.split('::').last || '').downcase
|
66
|
+
end
|
67
|
+
|
68
|
+
def initialize(name)
|
69
|
+
@name = name
|
70
|
+
# Allow the testcases to run as not root
|
71
|
+
resource_dir = File.join(Vmit::RUN_DIR, 'resources')
|
72
|
+
@lockfile_dir = File.join(resource_dir, resource_class, name)
|
73
|
+
FileUtils.mkdir_p @lockfile_dir
|
74
|
+
@lockfile_path = File.join(@lockfile_dir, 'lock')
|
75
|
+
end
|
76
|
+
|
77
|
+
# Creates a temporary resource with a random name
|
78
|
+
# @return [RefcountedResource]
|
79
|
+
def self.make_temp
|
80
|
+
name = File.basename(Dir::Tmpname.make_tmpname([resource_class, 'tmp'],
|
81
|
+
File.join(resource_dir, resource_class)))
|
82
|
+
self.new(name)
|
83
|
+
end
|
84
|
+
|
85
|
+
abstract_method :on_up
|
86
|
+
abstract_method :on_down
|
87
|
+
abstract_method :on_acquire
|
88
|
+
abstract_method :on_release
|
89
|
+
|
90
|
+
# Executes the given block.
|
91
|
+
# @yield calling before on_up once per group of
|
92
|
+
# processes using the same resurce, and
|
93
|
+
# on_acquire before executing the block.
|
94
|
+
# It will execute on_release after executing the
|
95
|
+
# block and the last process using the reource
|
96
|
+
# will call on_down
|
97
|
+
#
|
98
|
+
def auto
|
99
|
+
begin
|
100
|
+
Vmit.logger.debug "Using resource lock #{lockfile_path}"
|
101
|
+
File.open(lockfile_path, File::WRONLY | File::CREAT, 0666) do |f|
|
102
|
+
begin
|
103
|
+
if f.flock File::LOCK_EX | File::LOCK_NB
|
104
|
+
# we are the first ones, bring the resource up
|
105
|
+
self.on_up
|
106
|
+
end
|
107
|
+
|
108
|
+
if f.flock File::LOCK_SH
|
109
|
+
self.on_acquire
|
110
|
+
end
|
111
|
+
|
112
|
+
yield if block_given?
|
113
|
+
rescue Exception => e
|
114
|
+
Vmit.logger.error e.message
|
115
|
+
raise e
|
116
|
+
ensure
|
117
|
+
if f.flock File::LOCK_EX | File::LOCK_NB
|
118
|
+
self.on_down
|
119
|
+
end
|
120
|
+
on_release
|
121
|
+
f.flock File::LOCK_UN
|
122
|
+
end
|
123
|
+
end
|
124
|
+
rescue Exception => e
|
125
|
+
Vmit.logger.error e.message
|
126
|
+
raise e
|
127
|
+
ensure
|
128
|
+
File.unlink(lockfile_path)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
data/lib/vmit/utils.rb
ADDED
@@ -0,0 +1,103 @@
|
|
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 'rubygems'
|
22
|
+
require 'open4'
|
23
|
+
require 'progressbar'
|
24
|
+
require 'digest/sha1'
|
25
|
+
|
26
|
+
# Taken from Ruby on Rails
|
27
|
+
class Hash
|
28
|
+
# Returns a hash that represents the difference between two hashes.
|
29
|
+
#
|
30
|
+
# Examples:
|
31
|
+
#
|
32
|
+
# {1 => 2}.diff(1 => 2) # => {}
|
33
|
+
# {1 => 2}.diff(1 => 3) # => {1 => 2}
|
34
|
+
# {}.diff(1 => 2) # => {1 => 2}
|
35
|
+
# {1 => 2, 3 => 4}.diff(1 => 2) # => {3 => 4}
|
36
|
+
def diff(h2)
|
37
|
+
dup.delete_if { |k, v| h2[k] == v }.merge!(h2.dup.delete_if { |k, v| has_key?(k) })
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
module Vmit
|
42
|
+
|
43
|
+
module Utils
|
44
|
+
# @return [String] random MAC address
|
45
|
+
def self.random_mac_address
|
46
|
+
("%02x"%((rand 64).to_i*4|2))+(0..4).inject(""){|s,x|s+":%02x"%(rand 256).to_i}
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.uname(bzimage)
|
50
|
+
offset = 0
|
51
|
+
File.open(bzimage) do |f|
|
52
|
+
f.seek(0x20E)
|
53
|
+
offset = f.read(2).unpack('s')[0]
|
54
|
+
f.seek(offset + 0x200)
|
55
|
+
ver = f.read(128).unpack('Z*')[0]
|
56
|
+
return ver
|
57
|
+
end
|
58
|
+
nil
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.kernel_version(bzimage)
|
62
|
+
uname(bzimage).split(' ')[0]
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.sha1_file(filename)
|
66
|
+
sha1 = Digest::SHA1.new
|
67
|
+
File.open(filename) do |file|
|
68
|
+
buffer = ''
|
69
|
+
# Read the file 512 bytes at a time
|
70
|
+
while not file.eof
|
71
|
+
file.read(512, buffer)
|
72
|
+
sha1.update(buffer)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
sha1.to_s
|
76
|
+
end
|
77
|
+
|
78
|
+
# @param [String] uri uri to download
|
79
|
+
# @param [String] target where to donwload the file (directory)
|
80
|
+
def self.download_file(uri, target)
|
81
|
+
progress = ProgressBar.new(File.basename(uri.path), 100)
|
82
|
+
Net::HTTP.start(uri.host) do |http|
|
83
|
+
begin
|
84
|
+
file = open(target, 'wb')
|
85
|
+
http.request_get(uri.path) do |response|
|
86
|
+
dl_size = response.content_length
|
87
|
+
already_dl = 0
|
88
|
+
response.read_body do |segment|
|
89
|
+
already_dl += segment.length
|
90
|
+
if(already_dl != 0)
|
91
|
+
progress.set((already_dl * 100) / dl_size)
|
92
|
+
end
|
93
|
+
file.write(segment)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
ensure
|
97
|
+
file.close
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
end
|