vmit 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,273 @@
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'
22
+ require 'vmit/autoyast'
23
+ require 'vmit/kickstart'
24
+ require 'vmit/debian_preseed'
25
+
26
+ module Vmit
27
+
28
+ module Bootstrap
29
+
30
+ def self.arch
31
+ Cheetah.run('arch', :stdout => :capture).strip
32
+ end
33
+
34
+ def self.bootstrapper_for(location)
35
+ case
36
+ when local_iso
37
+ end
38
+ end
39
+
40
+ module MethodDebianPreseed
41
+ # @param [Hash] args Arguments for 1st stage
42
+ def execute_autoinstall(args)
43
+ auto_install_args = {}
44
+ preseed = Vmit::DebianPreseed.new
45
+
46
+ Dir.mktmpdir do |floppy_dir|
47
+ qemu_args = {:floppy => floppy_dir,
48
+ :append => "preseed/file=/floppy/preseed.cfg auto=true priority=critical",
49
+ :reboot => false}
50
+ qemu_args.merge!(auto_install_args)
51
+ # transform duplicates into an array
52
+ qemu_args.merge!(args) do |key, oldv, newv|
53
+ case key
54
+ when :append then [oldv, newv].flatten
55
+ else newv
56
+ end
57
+ end
58
+
59
+ # Configure the autoinstallation profile to persist eth0
60
+ # for the current MAC address
61
+ # The interface will be setup with DHCP by default.
62
+ # TODO: make this more flexible in the future?
63
+ #autoyast.name_network_device(vm[:mac_address], 'eth0')
64
+ File.write(File.join(floppy_dir, 'preseed.cfg'), preseed.to_txt)
65
+ Vmit.logger.info "Preseed: 1st stage."
66
+ vm.run(qemu_args)
67
+ Vmit.logger.info "Preseed: 2st stage."
68
+ # 2nd stage
69
+ vm.run(:reboot => false)
70
+ end
71
+ end
72
+ end
73
+
74
+ module MethodKickstart
75
+ # @param [Hash] args Arguments for 1st stage
76
+ def execute_autoinstall(args)
77
+ auto_install_args = {}
78
+ kickstart = Vmit::Kickstart.new
79
+
80
+ case media
81
+ when Vmit::VFS::URI
82
+ kickstart.install = location
83
+ when Vmit::VFS::ISO
84
+ kickstart.install = :cdrom
85
+ auto_install_args.merge!(:cdrom => location.to_s)
86
+ else raise ArgumentError.new("Unsupported autoinstallation: #{location}")
87
+ end
88
+
89
+ Dir.mktmpdir do |floppy_dir|
90
+ qemu_args = {:floppy => floppy_dir,
91
+ :append => "ks=floppy repo=#{kickstart.install}",
92
+ :reboot => false}
93
+ qemu_args.merge!(auto_install_args)
94
+ # transform duplicates into an array
95
+ qemu_args.merge!(args) do |key, oldv, newv|
96
+ case key
97
+ when :append then [oldv, newv].flatten
98
+ else newv
99
+ end
100
+ end
101
+
102
+ File.write(File.join(floppy_dir, 'ks.cfg'), kickstart.to_ks_script)
103
+ Vmit.logger.info "Kickstart: 1st stage."
104
+ vm.run(qemu_args)
105
+ end
106
+ end
107
+ end
108
+
109
+ module MethodAutoYaST
110
+ # @param [Hash] args Arguments for 1st stage
111
+ def execute_autoinstall(args)
112
+ auto_install_args = {}
113
+ auto_install_args.merge!(args)
114
+ kernel_append_arg = case media
115
+ when Vmit::VFS::URI then "install=#{location}"
116
+ when Vmit::VFS::ISO then 'install=cdrom'
117
+ else raise ArgumentError.new("Unsupported autoinstallation: #{location}")
118
+ end
119
+ auto_install_args.merge!(:append => kernel_append_arg)
120
+ if media.is_a?(Vmit::VFS::ISO)
121
+ auto_install_args.merge!(:cdrom => location.to_s)
122
+ end
123
+
124
+ Dir.mktmpdir do |floppy_dir|
125
+ qemu_args = {:floppy => floppy_dir,
126
+ :append => "autoyast=device://fd0/autoinst.xml",
127
+ :reboot => false}
128
+ # transform duplicates into an array
129
+ qemu_args.merge!(auto_install_args) do |key, oldv, newv|
130
+ case key
131
+ when :append then [oldv, newv].flatten
132
+ else newv
133
+ end
134
+ end
135
+
136
+ autoyast = Vmit::AutoYaST.new
137
+
138
+ # WTF SLE and openSUSE have different
139
+ # base pattern names
140
+ media.open('/content') do |content_file|
141
+ content_file.each_line do |line|
142
+ case line
143
+ when /^DISTRIBUTION (.+)$/
144
+ case $1
145
+ when /SUSE_SLE/ then autoyast.minimal_sle!
146
+ when /openSUSE/ then autoyast.minimal_opensuse!
147
+ end
148
+ end
149
+ end
150
+ end
151
+
152
+ # Configure the autoinstallation profile to persist eth0
153
+ # for the current MAC address
154
+ # The interface will be setup with DHCP by default.
155
+ # TODO: make this more flexible in the future?
156
+ #autoyast.name_network_device(vm[:mac_address], 'eth0')
157
+ File.write(File.join(floppy_dir, 'autoinst.xml'), autoyast.to_xml)
158
+ Vmit.logger.info "AutoYaST: 1st stage."
159
+ vm.run(qemu_args)
160
+ Vmit.logger.info "AutoYaST: 2st stage."
161
+ # 2nd stage
162
+ vm.run(:reboot => false)
163
+ end
164
+ end
165
+ end
166
+
167
+ module SUSEMedia
168
+ include MethodAutoYaST
169
+
170
+ def get_initrd
171
+ media.open("/boot/#{Vmit::Bootstrap.arch}/loader/initrd")
172
+ end
173
+
174
+ def get_kernel
175
+ media.open("/boot/#{Vmit::Bootstrap.arch}/loader/linux")
176
+ end
177
+ end
178
+
179
+ module FedoraMedia
180
+ include MethodKickstart
181
+
182
+ def get_initrd
183
+ media.open("/images/pxeboot/initrd.img")
184
+ end
185
+
186
+ def get_kernel
187
+ media.open("/images/pxeboot/vmlinuz")
188
+ end
189
+ end
190
+
191
+ module DebianMedia
192
+ include MethodDebianPreseed
193
+
194
+ def get_initrd
195
+ arch = Vmit::Bootstrap.arch.gsub(/x86_64/, 'amd64')
196
+ media.open("/main/installer-#{arch}/current/images/netboot/debian-installer/#{arch}/initrd.gz")
197
+ end
198
+
199
+ def get_kernel
200
+ arch = Vmit::Bootstrap.arch.gsub(/x86_64/, 'amd64')
201
+ media.open("/main/installer-#{arch}/current/images/netboot/debian-installer/#{arch}/linux")
202
+ end
203
+ end
204
+
205
+ # Boostraps a vm from a SUSE repository
206
+ class FromMedia
207
+
208
+ attr_reader :vm
209
+ attr_reader :media
210
+ attr_reader :location
211
+
212
+ # @param [URI] location
213
+ def self.accept?(location)
214
+ # either a local ISO or a remote repository
215
+ # (and not a remote file, but we don't have
216
+ # a good way to check)
217
+ Vmit::VFS::ISO.accept?(location) ||
218
+ (Vmit::VFS::URI.accept?(location) &&
219
+ File.extname(location.to_s) == '')
220
+ end
221
+
222
+ def initialize(vm, location)
223
+ @location = location
224
+ @vm = vm
225
+ @media = Vmit::VFS.from(location)
226
+
227
+ # TODO FIXME we need a clever way to detect the
228
+ # location distro type. I could uname the kernel, but
229
+ # I need the type to know the location.
230
+ media_handler = case location.to_s.downcase
231
+ when /fedora|redhat|centos/ then FedoraMedia
232
+ when /suse/ then SUSEMedia
233
+ when /debian/ then DebianMedia
234
+ else
235
+ raise "Don't know how to bootstrap media #{location}"
236
+ end
237
+ self.extend media_handler
238
+
239
+ @boot_kernel = get_kernel
240
+ @boot_initrd = get_initrd
241
+ end
242
+
243
+ def execute
244
+ args = {}
245
+ args.merge!({:kernel => @boot_kernel.path, :initrd => @boot_initrd.path})
246
+ execute_autoinstall(args)
247
+ end
248
+ end
249
+
250
+ class FromImage
251
+
252
+ # @param [URI] location
253
+ def self.accept?(location)
254
+ uri = case location
255
+ when ::URI then location
256
+ else ::URI.parse(location.to_s)
257
+ end
258
+ return false unless ['.raw', '.qcow2'].include?(File.extname(uri.to_s))
259
+ uri.scheme == 'http' || File.exist?(uri.to_s)
260
+ end
261
+
262
+ def initialize(vm, location)
263
+ @location = location
264
+ #http://download.suse.de/ibs/Devel:/Galaxy:/Manager:/1.7:/Appliance/images/SUSE_Manager_Server_pg_Devel.x86_64-1.7.0-Build3.126.raw.xz
265
+ end
266
+
267
+ def execute
268
+ Vmit.logger.info "From media!!!"
269
+ end
270
+ end
271
+
272
+ end
273
+ end
@@ -0,0 +1,64 @@
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 'erb'
22
+
23
+ module Vmit
24
+
25
+ # Some good references here:
26
+ # http://www.hps.com/~tpg/notebook/autoinstall.php
27
+ class DebianPreseed
28
+
29
+ def to_txt
30
+ template = ERB.new <<-EOF
31
+ d-i debian-installer/locale string en_US
32
+ d-i console-tools/archs select at
33
+ d-i console-keymaps-at/keymap select American English
34
+ d-i debian-installer/keymap string us
35
+ d-i netcfg/get_hostname string unassigned-hostname
36
+ d-i netcfg/get_hostname seen true
37
+ d-i netcfg/get_domain string unassigned-domain
38
+ d-i netcfg/get_domain seen true
39
+ d-i mirror/protocol string ftp
40
+ d-i mirror/ftp/hostname string ftp.de.debian.org
41
+ d-i mirror/ftp/directory string /debian/
42
+ d-i mirror/ftp/proxy string
43
+
44
+ d-i partman-auto/method string regular
45
+ d-i partman-partitioning/confirm_write_new_label boolean true
46
+ d-i partman/choose_partition select finish
47
+ d-i partman/confirm boolean true
48
+ d-i partman/confirm_nooverwrite boolean true
49
+
50
+ d-i clock-setup/utc boolean true
51
+ d-i time/zone string US/Eastern
52
+ d-i clock-setup/ntp boolean true
53
+ popularity-contest popularity-contest/participate boolean false
54
+ d-i pkgsel/include string ssh rsync initrd-tools cramfsprogs lzop
55
+ d-i passwd/root-password password linux
56
+ d-i passwd/root-password-again password linux
57
+ d-i passwd/make-user boolean false
58
+ d-i grub-installer/only_debian boolean true
59
+ EOF
60
+ return template.result(binding)
61
+ end
62
+
63
+ end
64
+ end
data/lib/vmit/ext.rb ADDED
@@ -0,0 +1,38 @@
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
+
22
+ module Vmit
23
+ module Ext
24
+
25
+ module Hash
26
+ def symbolize_keys
27
+ Hash[map{|(k,v)| [k.to_sym,v]}]
28
+ end
29
+
30
+ def symbolize_keys!
31
+ replace(symbolize_keys)
32
+ end
33
+ end
34
+
35
+ end
36
+ end
37
+
38
+ Hash.send(:include, Vmit::Ext::Hash)
@@ -0,0 +1,67 @@
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'
22
+ require 'erb'
23
+
24
+ module Vmit
25
+
26
+ class Kickstart
27
+
28
+ attr_accessor :install
29
+
30
+ # ks=floppy
31
+ def initialize
32
+ end
33
+
34
+ def to_ks_script
35
+ template = ERB.new <<-EOF
36
+ cmdline
37
+ halt
38
+ rootpw linux
39
+ lang en_US.UTF-8
40
+ keyboard us
41
+ timezone --utc America/New_York
42
+ bootloader --location=mbr --driveorder=sda --append="rhgb quiet"
43
+ install
44
+ <% if install.is_a?(String) || install.is_a?(::URI)%>
45
+ url --url=<%= install.to_s.strip %>
46
+ <% else %>
47
+ <%= install %>
48
+ <% end %>
49
+ network --device eth0 --bootproto dhcp
50
+ zerombr yes
51
+ clearpart --all --initlabel
52
+ autopart
53
+ %packages --nobase
54
+ @core
55
+ @server-policy
56
+ wget
57
+ mc
58
+
59
+ %end
60
+ EOF
61
+ template.result(binding)
62
+ end
63
+
64
+
65
+ end
66
+
67
+ end
@@ -0,0 +1,66 @@
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 'logger'
22
+ require 'cheetah'
23
+
24
+ module Vmit
25
+
26
+ # remote log service for
27
+ # qemu ifup ifdown scripts
28
+ class LogServer
29
+ def method_missing(name, *args)
30
+ Vmit.logger.send(name, *args)
31
+ end
32
+ end
33
+
34
+ # Cheetah says it supports a logger
35
+ # for debugging but then adds entries
36
+ # with INFO instead of DEBUG
37
+ class CheetahLoggerAdapter
38
+ def initialize(logger)
39
+ @logger = logger
40
+ end
41
+
42
+ def info(message)
43
+ @logger.debug(message)
44
+ end
45
+
46
+ def error(message)
47
+ @logger.error(message)
48
+ end
49
+ end
50
+
51
+ def self.logger=(logger)
52
+ @logger = logger
53
+ end
54
+
55
+ def self.logger
56
+ if @logger.nil?
57
+ logger = Logger.new(STDERR)
58
+ logger.level = Logger::INFO
59
+ logger.level = Logger::DEBUG if ENV['DEBUG']
60
+ Vmit.logger = logger
61
+ Cheetah.default_options = {:logger => CheetahLoggerAdapter.new(logger)}
62
+ end
63
+ @logger
64
+ end
65
+
66
+ end