vmit 0.0.3
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.
- 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
|