Merge lp:~soren/vmbuilder/0.12.refactoring into lp:vmbuilder
- 0.12.refactoring
- Merge into 0.12
Proposed by
Soren Hansen
Status: | Merged |
---|---|
Merged at revision: | not available |
Proposed branch: | lp:~soren/vmbuilder/0.12.refactoring |
Merge into: | lp:vmbuilder |
Diff against target: |
3100 lines (+1205/-727) 33 files modified
VMBuilder/__init__.py (+31/-5) VMBuilder/disk.py (+84/-58) VMBuilder/distro.py (+53/-3) VMBuilder/exception.py (+1/-1) VMBuilder/frontend.py (+30/-27) VMBuilder/hypervisor.py (+68/-5) VMBuilder/log.py (+1/-1) VMBuilder/plugins/__init__.py (+40/-33) VMBuilder/plugins/cli/__init__.py (+131/-72) VMBuilder/plugins/ec2/__init__.py (+43/-43) VMBuilder/plugins/firstscripts/__init__.py (+20/-20) VMBuilder/plugins/kvm/vm.py (+13/-9) VMBuilder/plugins/libvirt/__init__.py (+14/-14) VMBuilder/plugins/network/__init__.py (+58/-30) VMBuilder/plugins/postinst/__init__.py (+22/-22) VMBuilder/plugins/ubuntu/dapper.py (+162/-113) VMBuilder/plugins/ubuntu/distro.py (+135/-97) VMBuilder/plugins/ubuntu/edgy.py (+5/-5) VMBuilder/plugins/ubuntu/hardy.py (+8/-5) VMBuilder/plugins/ubuntu/intrepid.py (+1/-1) VMBuilder/plugins/ubuntu/jaunty.py (+5/-5) VMBuilder/plugins/ubuntu/karmic.py (+2/-2) VMBuilder/plugins/ubuntu/suite.py (+2/-2) VMBuilder/plugins/ubuntu/templates/dapper_fstab.tmpl (+1/-0) VMBuilder/plugins/virtualbox/vm.py (+8/-8) VMBuilder/plugins/vmware/vm.py (+13/-13) VMBuilder/plugins/xen/vm.py (+16/-16) VMBuilder/util.py (+30/-28) VMBuilder/vm.py (+0/-74) test/disk_tests.py (+196/-2) test/plugin_tests.py (+1/-1) test/ubuntu_tests.py (+2/-3) test/util_tests.py (+9/-9) |
To merge this branch: | bzr merge lp:~soren/vmbuilder/0.12.refactoring |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
VMBuilder | Pending | ||
Review via email: mp+19624@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'VMBuilder/__init__.py' |
2 | --- VMBuilder/__init__.py 2010-01-22 13:27:16 +0000 |
3 | +++ VMBuilder/__init__.py 2010-02-18 16:03:14 +0000 |
4 | @@ -31,7 +31,8 @@ |
5 | # Internal bookkeeping |
6 | distros = {} |
7 | hypervisors = {} |
8 | -_plugins = [] |
9 | +_distro_plugins = [] |
10 | +_hypervisor_plugins = [] |
11 | frontends = {} |
12 | frontend = None |
13 | |
14 | @@ -41,18 +42,35 @@ |
15 | """Register a hypervisor plugin with VMBuilder""" |
16 | hypervisors[cls.arg] = cls |
17 | |
18 | +def get_hypervisor(name): |
19 | + if name in hypervisors: |
20 | + return hypervisors[name] |
21 | + else: |
22 | + raise VMBuilderUserError('No such hypervisor. Available hypervisors: %s' % (' '.join(hypervisors.keys()))) |
23 | + |
24 | def register_distro(cls): |
25 | """Register a distro plugin with VMBuilder""" |
26 | distros[cls.arg] = cls |
27 | |
28 | +def get_distro(name): |
29 | + if name in distros: |
30 | + return distros[name] |
31 | + else: |
32 | + raise VMBuilderUserError('No such distro. Available distros: %s' % (' '.join(distros.keys()))) |
33 | + |
34 | def register_frontend(cls): |
35 | """Register a frontend plugin with VMBuilder""" |
36 | frontends[cls.arg] = cls |
37 | |
38 | -def register_plugin(cls): |
39 | - """Register a plugin with VMBuilder""" |
40 | - _plugins.append(cls) |
41 | - _plugins.sort(key=lambda x: x.priority) |
42 | +def register_distro_plugin(cls): |
43 | + """Register a plugin with VMBuilder""" |
44 | + _distro_plugins.append(cls) |
45 | + _distro_plugins.sort(key=lambda x: x.priority) |
46 | + |
47 | +def register_hypervisor_plugin(cls): |
48 | + """Register a plugin with VMBuilder""" |
49 | + _hypervisor_plugins.append(cls) |
50 | + _hypervisor_plugins.sort(key=lambda x: x.priority) |
51 | |
52 | def set_frontend(arg): |
53 | global frontend |
54 | @@ -65,5 +83,13 @@ |
55 | """This is sort of weird, but a handy shortcut, if you want to use one of the frontends""" |
56 | return(frontend.run()) |
57 | |
58 | +def get_version_info(): |
59 | + import vcsversion |
60 | + info = vcsversion.version_info |
61 | + info['major'] = 0 |
62 | + info['minor'] = 11 |
63 | + info['micro'] = 3 |
64 | + return info |
65 | + |
66 | logging.debug('Loading plugins') |
67 | VMBuilder.plugins.load_plugins() |
68 | |
69 | === modified file 'VMBuilder/disk.py' |
70 | --- VMBuilder/disk.py 2009-10-23 07:17:47 +0000 |
71 | +++ VMBuilder/disk.py 2010-02-18 16:03:14 +0000 |
72 | @@ -18,7 +18,9 @@ |
73 | # |
74 | # Virtual disk management |
75 | |
76 | +import fcntl |
77 | import logging |
78 | +import os |
79 | import os.path |
80 | import re |
81 | import stat |
82 | @@ -27,6 +29,7 @@ |
83 | import VMBuilder |
84 | from VMBuilder.util import run_cmd |
85 | from VMBuilder.exception import VMBuilderUserError, VMBuilderException |
86 | +from struct import unpack |
87 | |
88 | TYPE_EXT2 = 0 |
89 | TYPE_EXT3 = 1 |
90 | @@ -34,62 +37,63 @@ |
91 | TYPE_SWAP = 3 |
92 | |
93 | class Disk(object): |
94 | - def __init__(self, vm, size='5G', preallocated=False, filename=None): |
95 | + def __init__(self, vm, filename, size=None): |
96 | """ |
97 | @type size: string or number |
98 | @param size: The size of the disk image (passed to L{parse_size}) |
99 | |
100 | - @type preallocated: boolean |
101 | - @param preallocated: if True, the disk image already exists and will not be created (useful for raw devices) |
102 | - |
103 | @type filename: string |
104 | - @param filename: force a certain filename or to give the name of the preallocated disk image |
105 | + @param filename: filename of the disk image. If size is given, this |
106 | + file will be overwritten with an image of the given size |
107 | """ |
108 | |
109 | - # We need this for "introspection" |
110 | self.vm = vm |
111 | - |
112 | - # Perhaps this should be the frontend's responsibility? |
113 | - self.size = parse_size(size) |
114 | - |
115 | - self.preallocated = preallocated |
116 | - |
117 | - # If filename isn't given, make one up |
118 | - if filename: |
119 | - self.filename = filename |
120 | + self.filename = filename |
121 | + self.preallocated = False |
122 | + |
123 | + if not os.path.exists(self.filename): |
124 | + if not size: |
125 | + raise VMBuilderUserError('%s does not exist, but no size was given.' % (self.filename)) |
126 | + self.size = parse_size(size) |
127 | else: |
128 | - if self.preallocated: |
129 | - raise VMBuilderUserError('Preallocated was set, but no filename given') |
130 | - self.filename = 'disk%d.img' % len(self.vm.disks) |
131 | + if size: |
132 | + raise VMBuilderUserError('%s exists, but size was given.' % (self.filename)) |
133 | + self.preallocated = True |
134 | + self.size = detect_size(self.filename) |
135 | |
136 | self.partitions = [] |
137 | |
138 | - def devletters(self): |
139 | + def devletters(self, vm): |
140 | """ |
141 | + @type vm: VM object |
142 | + @param vm: The VM object to which the disk belongs L{parse_size}) |
143 | + |
144 | @rtype: string |
145 | @return: the series of letters that ought to correspond to the device inside |
146 | the VM. E.g. the first disk of a VM would return 'a', while the 702nd would return 'zz' |
147 | """ |
148 | |
149 | - return index_to_devname(self.vm.disks.index(self)) |
150 | - |
151 | - def create(self, directory): |
152 | - """ |
153 | - Creates the disk image (unless preallocated), partitions it, creates the partition mapping devices and mkfs's the partitions |
154 | - |
155 | - @type directory: string |
156 | - @param directory: If set, the disk image is created in this directory |
157 | - """ |
158 | - |
159 | - if not self.preallocated: |
160 | - if directory: |
161 | - self.filename = '%s/%s' % (directory, self.filename) |
162 | - logging.info('Creating disk image: %s' % self.filename) |
163 | + return index_to_devname(vm.disks.index(self)) |
164 | + |
165 | + def create(self): |
166 | + """ |
167 | + Creates the disk image (unless preallocated) |
168 | + |
169 | + It is safe to call this method even if the disk image already exists, |
170 | + in which case, it's a no-op. |
171 | + |
172 | + Once this method returns, self.filename points to whatever holds the virtual disk |
173 | + (be it a file, partition, logical volume, etc.). |
174 | + """ |
175 | + |
176 | + if not os.path.exists(self.filename): |
177 | + logging.info('Creating disk image: "%s" of size: %dMB' % (self.filename, self.size)) |
178 | run_cmd(qemu_img_path(), 'create', '-f', 'raw', self.filename, '%dM' % self.size) |
179 | - os.chmod(self.filename, stat.S_IRUSR | stat.S_IWUSR) |
180 | |
181 | - # From here, we assume that self.filename refers to whatever holds the disk image, |
182 | - # be it a file, a partition, logical volume, actual disk.. |
183 | + def partition(self): |
184 | + """ |
185 | + Partitions the disk image. Call this once you've added all partitions. |
186 | + """ |
187 | |
188 | logging.info('Adding partition table to disk image: %s' % self.filename) |
189 | run_cmd('parted', '--script', self.filename, 'mklabel', 'msdos') |
190 | @@ -98,6 +102,10 @@ |
191 | for part in self.partitions: |
192 | part.create(self) |
193 | |
194 | + def map_partitions(self): |
195 | + """ |
196 | + Create loop devices corresponding to the partitions |
197 | + """ |
198 | logging.info('Creating loop devices corresponding to the created partitions') |
199 | self.vm.add_clean_cb(lambda : self.unmap(ignore_fail=True)) |
200 | kpartx_output = run_cmd('kpartx', '-av', self.filename) |
201 | @@ -113,11 +121,12 @@ |
202 | for line in parts: |
203 | mapdevs.append(line.split(' ')[2]) |
204 | for (part, mapdev) in zip(self.partitions, mapdevs): |
205 | - part.mapdev = '/dev/mapper/%s' % mapdev |
206 | + part.set_filename('/dev/mapper/%s' % mapdev) |
207 | |
208 | # At this point, all partitions are created and their mapping device has been |
209 | - # created and set as .mapdev |
210 | + # created and set as .filename |
211 | |
212 | + def mkfs(self): |
213 | # Adds a filesystem to the partition |
214 | logging.info("Creating file systems") |
215 | for part in self.partitions: |
216 | @@ -158,16 +167,15 @@ |
217 | @type mntpnt: string |
218 | @param mntpnt: Intended mountpoint inside the guest of the new partition |
219 | """ |
220 | + length = parse_size(length) |
221 | end = begin+length-1 |
222 | - logging.debug("add_part - begin %d, length %d, end %d" % (begin, length, end)) |
223 | + logging.debug("add_part - begin %d, length %d, end %d, type %s, mntpnt %s" % (begin, length, end, type, mntpnt)) |
224 | for part in self.partitions: |
225 | if (begin >= part.begin and begin <= part.end) or \ |
226 | (end >= part.begin and end <= part.end): |
227 | - raise Exception('Partitions are overlapping') |
228 | - if begin > end: |
229 | - raise Exception('Partition\'s last block is before its first') |
230 | - if begin < 0 or end > self.size: |
231 | - raise Exception('Partition is out of bounds. start=%d, end=%d, disksize=%d' % (begin,end,self.size)) |
232 | + raise VMBuilderUserError('Partitions are overlapping') |
233 | + if begin < 0 or end > self.size: |
234 | + raise VMBuilderUserError('Partition is out of bounds. start=%d, end=%d, disksize=%d' % (begin,end,self.size)) |
235 | part = self.Partition(disk=self, begin=begin, end=end, type=str_to_type(type), mntpnt=mntpnt) |
236 | self.partitions.append(part) |
237 | |
238 | @@ -211,6 +219,12 @@ |
239 | self.type = type |
240 | self.mntpnt = mntpnt |
241 | self.mapdev = None |
242 | + self.fs = Filesystem(vm=self.disk.vm, preallocated=True, type=self.type, mntpnt=self.mntpnt) |
243 | + |
244 | + def set_filename(self, filename): |
245 | + print 'set_filename called' |
246 | + self.filename = filename |
247 | + self.fs.filename = filename |
248 | |
249 | def parted_fstype(self): |
250 | """ |
251 | @@ -226,9 +240,6 @@ |
252 | |
253 | def mkfs(self): |
254 | """Adds Filesystem object""" |
255 | - if not self.mapdev: |
256 | - raise Exception('We can\'t mkfs before we have a mapper device') |
257 | - self.fs = Filesystem(self.disk.vm, preallocated=True, filename=self.mapdev, type=self.type, mntpnt=self.mntpnt) |
258 | self.fs.mkfs() |
259 | |
260 | def get_grub_id(self): |
261 | @@ -245,11 +256,10 @@ |
262 | return self.disk.partitions.index(self) |
263 | |
264 | class Filesystem(object): |
265 | - def __init__(self, vm, size=0, preallocated=False, type=None, mntpnt=None, filename=None, devletter='a', device='', dummy=False): |
266 | + def __init__(self, vm=None, size=0, preallocated=False, type=None, mntpnt=None, filename=None, devletter='a', device='', dummy=False): |
267 | self.vm = vm |
268 | self.filename = filename |
269 | self.size = parse_size(size) |
270 | - self.preallocated = preallocated |
271 | self.devletter = devletter |
272 | self.device = device |
273 | self.dummy = dummy |
274 | @@ -266,7 +276,7 @@ |
275 | |
276 | def create(self): |
277 | logging.info('Creating filesystem: %s, size: %d, dummy: %s' % (self.mntpnt, self.size, repr(self.dummy))) |
278 | - if not self.preallocated: |
279 | + if not os.path.exists(self.filename): |
280 | logging.info('Not preallocated, so we create it.') |
281 | if not self.filename: |
282 | if self.mntpnt: |
283 | @@ -288,6 +298,8 @@ |
284 | self.mkfs() |
285 | |
286 | def mkfs(self): |
287 | + if not self.filename: |
288 | + raise VMBuilderException('We can\'t mkfs if filename is not set. Did you forget to call .create()?') |
289 | if not self.dummy: |
290 | cmd = self.mkfs_fstype() + [self.filename] |
291 | run_cmd(*cmd) |
292 | @@ -297,12 +309,12 @@ |
293 | self.uuid = run_cmd('blkid', '-sUUID', '-ovalue', self.filename).rstrip() |
294 | |
295 | def mkfs_fstype(self): |
296 | - if self.vm.suite in ['dapper', 'edgy', 'feisty', 'gutsy']: |
297 | - logging.debug('%s: 128 bit inode' % self.vm.suite) |
298 | - return { TYPE_EXT2: ['mkfs.ext2', '-F'], TYPE_EXT3: ['mkfs.ext3', '-I 128', '-F'], TYPE_XFS: ['mkfs.xfs'], TYPE_SWAP: ['mkswap'] }[self.type] |
299 | - else: |
300 | - logging.debug('%s: 256 bit inode' % self.vm.suite) |
301 | - return { TYPE_EXT2: ['mkfs.ext2', '-F'], TYPE_EXT3: ['mkfs.ext3', '-F'], TYPE_XFS: ['mkfs.xfs'], TYPE_SWAP: ['mkswap'] }[self.type] |
302 | + map = { TYPE_EXT2: ['mkfs.ext2', '-F'], TYPE_EXT3: ['mkfs.ext3', '-F'], TYPE_XFS: ['mkfs.xfs'], TYPE_SWAP: ['mkswap'] } |
303 | + |
304 | + if not self.vm.distro.has_256_bit_inode_ext3_support(): |
305 | + map[TYPE_EXT3] = ['mkfs.ext3', '-I 128', '-F'] |
306 | + |
307 | + return map[self.type] |
308 | |
309 | def fstab_fstype(self): |
310 | return { TYPE_EXT2: 'ext2', TYPE_EXT3: 'ext3', TYPE_XFS: 'xfs', TYPE_SWAP: 'swap' }[self.type] |
311 | @@ -310,10 +322,10 @@ |
312 | def fstab_options(self): |
313 | return 'defaults' |
314 | |
315 | - def mount(self): |
316 | + def mount(self, rootmnt): |
317 | if (self.type != TYPE_SWAP) and not self.dummy: |
318 | logging.debug('Mounting %s', self.mntpnt) |
319 | - self.mntpath = '%s%s' % (self.vm.rootmnt, self.mntpnt) |
320 | + self.mntpath = '%s%s' % (rootmnt, self.mntpnt) |
321 | if not os.path.exists(self.mntpath): |
322 | os.makedirs(self.mntpath) |
323 | run_cmd('mount', '-o', 'loop', self.filename, self.mntpath) |
324 | @@ -426,6 +438,20 @@ |
325 | return suffix |
326 | return index_to_devname(index / 26 -1, string.ascii_lowercase[index % 26]) + suffix |
327 | |
328 | +def detect_size(filename): |
329 | + st = os.stat(filename) |
330 | + if stat.S_ISREG(st.st_mode): |
331 | + return st.st_size / 1024*1024 |
332 | + elif stat.S_ISBLK(st.st_mode): |
333 | + # I really wish someone would make these available in Python |
334 | + BLKGETSIZE64 = 2148012658 |
335 | + fp = open(filename, 'r') |
336 | + fd = fp.fileno() |
337 | + s = fcntl.ioctl(fd, BLKGETSIZE64, ' '*8) |
338 | + return unpack('L', s)[0] / 1024*1024 |
339 | + |
340 | + raise VMBuilderException('No idea how to find the size of %s' % filename) |
341 | + |
342 | def qemu_img_path(): |
343 | exes = ['kvm-img', 'qemu-img'] |
344 | for dir in os.environ['PATH'].split(os.path.pathsep): |
345 | |
346 | === modified file 'VMBuilder/distro.py' |
347 | --- VMBuilder/distro.py 2009-06-10 13:40:41 +0000 |
348 | +++ VMBuilder/distro.py 2010-02-18 16:03:14 +0000 |
349 | @@ -17,10 +17,60 @@ |
350 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
351 | # |
352 | # Distro super class |
353 | -from VMBuilder.util import run_cmd |
354 | +from VMBuilder.util import run_cmd, call_hooks |
355 | import VMBuilder.plugins |
356 | - |
357 | -class Distro(VMBuilder.plugins.Plugin): |
358 | +import logging |
359 | + |
360 | +class Context(VMBuilder.plugins.Plugin): |
361 | + def __init__(self): |
362 | + self._config = {} |
363 | + super(Context, self).__init__(self) |
364 | + self.plugins = [plugin_class(self) for plugin_class in self.plugin_classes] |
365 | + self.plugins.sort(key=lambda x:x.priority) |
366 | + self._cleanup_cbs = [] |
367 | + |
368 | + # Cleanup |
369 | + def cleanup(self): |
370 | + logging.info("Cleaning up") |
371 | + while len(self._cleanup_cbs) > 0: |
372 | + self._cleanup_cbs.pop(0)() |
373 | + |
374 | + def add_clean_cb(self, cb): |
375 | + self._cleanup_cbs.insert(0, cb) |
376 | + |
377 | + def add_clean_cmd(self, *argv, **kwargs): |
378 | + cb = lambda : run_cmd(*argv, **kwargs) |
379 | + self.add_clean_cb(cb) |
380 | + return cb |
381 | + |
382 | + def cancel_cleanup(self, cb): |
383 | + try: |
384 | + self._cleanup_cbs.remove(cb) |
385 | + except ValueError, e: |
386 | + # Wasn't in there. No worries. |
387 | + pass |
388 | + |
389 | + def call_hooks(self, *args, **kwargs): |
390 | + try: |
391 | + call_hooks(self, *args, **kwargs) |
392 | + except Exception, e: |
393 | + #self.cleanup() |
394 | + raise |
395 | + |
396 | +class Distro(Context): |
397 | + def __init__(self): |
398 | + self.plugin_classes = VMBuilder._distro_plugins |
399 | + super(Distro, self).__init__() |
400 | + |
401 | + def set_chroot_dir(self, chroot_dir): |
402 | + self.chroot_dir = chroot_dir |
403 | + |
404 | + def build_chroot(self): |
405 | + self.call_hooks('preflight_check') |
406 | + self.call_hooks('set_defaults') |
407 | + self.call_hooks('bootstrap') |
408 | + self.call_hooks('configure_os') |
409 | + |
410 | def has_xen_support(self): |
411 | """Install the distro into destdir""" |
412 | raise NotImplemented('Distro subclasses need to implement the has_xen_support method') |
413 | |
414 | === modified file 'VMBuilder/exception.py' |
415 | --- VMBuilder/exception.py 2009-06-10 13:40:41 +0000 |
416 | +++ VMBuilder/exception.py 2010-02-18 16:03:14 +0000 |
417 | @@ -22,6 +22,6 @@ |
418 | """Something failed inside VMBuilder""" |
419 | pass |
420 | |
421 | -class VMBuilderUserError(Exception): |
422 | +class VMBuilderUserError(VMBuilderException): |
423 | """The user did something silly.""" |
424 | pass |
425 | |
426 | === modified file 'VMBuilder/frontend.py' |
427 | --- VMBuilder/frontend.py 2009-06-10 13:40:41 +0000 |
428 | +++ VMBuilder/frontend.py 2010-02-18 16:03:14 +0000 |
429 | @@ -18,33 +18,36 @@ |
430 | # |
431 | # Frontend interface and classes |
432 | |
433 | -import VMBuilder |
434 | -import optparse |
435 | +import VMBuilder.plugins |
436 | |
437 | -class Frontend(object): |
438 | +class Frontend(VMBuilder.plugins.Plugin): |
439 | def __init__(self): |
440 | - self.settings = [] |
441 | - |
442 | - def setting_group(self, help=None): |
443 | - return self.SettingsGroup(help) |
444 | - |
445 | - def add_setting_group(self, group): |
446 | - self.settings.append(group) |
447 | - |
448 | - def add_setting(self, **kwargs): |
449 | - self.settings.append(Setting(**kwargs)) |
450 | - |
451 | - setting_types = ['store', 'store'] |
452 | - class Setting(object): |
453 | - def __init__(self, **kwargs): |
454 | - self.shortarg = kwargs.get('shortarg', None) |
455 | - self.longarg = kwargs.get('shortarg', None) |
456 | - self.default = kwargs.get('default', None) |
457 | - self.help = kwargs.get('help', None) |
458 | - type = kwargs.get('type', 'store') |
459 | - if type not in setting_types: |
460 | - raise VMBuilderException("Invalid option type: %s" % type) |
461 | - |
462 | - class SettingsGroup(Setting): |
463 | - pass |
464 | + self._setting_groups = [] |
465 | + self._config = {} |
466 | + self.context = self |
467 | + |
468 | +# self.settings = [] |
469 | + |
470 | +# def setting_group(self, help=None): |
471 | +# return self.SettingsGroup(help) |
472 | +# |
473 | +# def add_setting_group(self, group): |
474 | +# self.settings.append(group) |
475 | +# |
476 | +# def add_setting(self, **kwargs): |
477 | +# self.settings.append(Setting(**kwargs)) |
478 | +# |
479 | +# setting_types = ['store', 'store'] |
480 | +# class Setting(object): |
481 | +# def __init__(self, **kwargs): |
482 | +# self.shortarg = kwargs.get('shortarg', None) |
483 | +# self.longarg = kwargs.get('shortarg', None) |
484 | +# self.default = kwargs.get('default', None) |
485 | +# self.help = kwargs.get('help', None) |
486 | +# type = kwargs.get('type', 'store') |
487 | +# if type not in setting_types: |
488 | +# raise VMBuilderException("Invalid option type: %s" % type) |
489 | +# |
490 | +# class SettingsGroup(Setting): |
491 | +# pass |
492 | |
493 | |
494 | === modified file 'VMBuilder/hypervisor.py' |
495 | --- VMBuilder/hypervisor.py 2009-06-10 13:40:41 +0000 |
496 | +++ VMBuilder/hypervisor.py 2010-02-18 16:03:14 +0000 |
497 | @@ -18,12 +18,75 @@ |
498 | # |
499 | # Hypervisor super class |
500 | |
501 | -import VMBuilder.plugins |
502 | +import logging |
503 | +import VMBuilder.distro |
504 | +import VMBuilder.disk |
505 | +from VMBuilder.util import call_hooks, run_cmd, tmpdir |
506 | |
507 | STORAGE_DISK_IMAGE = 0 |
508 | STORAGE_FS_IMAGE = 1 |
509 | |
510 | -class Hypervisor(VMBuilder.plugins.Plugin): |
511 | - def finalize(self): |
512 | - raise NotImplemented('Hypervisor subclasses need to implement the finalize method') |
513 | - |
514 | +class Hypervisor(VMBuilder.distro.Context): |
515 | + def __init__(self, distro): |
516 | + self.plugin_classes = VMBuilder._hypervisor_plugins |
517 | + super(Hypervisor, self).__init__() |
518 | + self.plugins += [distro] |
519 | + self.distro = distro |
520 | + self.filesystems = [] |
521 | + self.disks = [] |
522 | + self.nics = [] |
523 | + |
524 | + def add_disk(self, *args, **kwargs): |
525 | + """Adds a disk image to the virtual machine""" |
526 | + from VMBuilder.disk import Disk |
527 | + disk = Disk(self, *args, **kwargs) |
528 | + self.disks.append(disk) |
529 | + return disk |
530 | + |
531 | + def install_os(self): |
532 | + self.nics = [self.NIC()] |
533 | + self.call_hooks('configure_networking', self.nics) |
534 | + self.call_hooks('configure_mounting', self.disks, self.filesystems) |
535 | + |
536 | + self.chroot_dir = tmpdir() |
537 | + self.call_hooks('mount_partitions', self.chroot_dir) |
538 | + run_cmd('rsync', '-aHA', '%s/' % self.distro.chroot_dir, self.chroot_dir) |
539 | + self.distro.set_chroot_dir(self.chroot_dir) |
540 | + self.call_hooks('install_bootloader', self.chroot_dir, self.disks) |
541 | + self.call_hooks('install_kernel', self.chroot_dir) |
542 | + self.call_hooks('unmount_partitions') |
543 | + |
544 | + def finalise(self, destdir): |
545 | + self.call_hooks('convert', self.disks, destdir) |
546 | + self.call_hooks('deploy', destdir) |
547 | + |
548 | + def mount_partitions(self, mntdir): |
549 | + """Mounts all the vm's partitions and filesystems below .rootmnt""" |
550 | + logging.info('Mounting target filesystems') |
551 | + for disk in self.disks: |
552 | + disk.create() |
553 | + disk.partition() |
554 | + disk.map_partitions() |
555 | + disk.mkfs() |
556 | + fss = VMBuilder.disk.get_ordered_filesystems(self) |
557 | + for fs in fss: |
558 | + fs.mount(mntdir) |
559 | + self.distro.post_mount(fs) |
560 | + |
561 | + def unmount_partitions(self): |
562 | + """Unmounts all the vm's partitions and filesystems""" |
563 | + logging.info('Unmounting target filesystem') |
564 | + fss = VMBuilder.disk.get_ordered_filesystems(self) |
565 | + fss.reverse() |
566 | + for fs in fss: |
567 | + fs.umount() |
568 | + for disk in self.disks: |
569 | + disk.unmap() |
570 | + |
571 | + def convert_disks(self, disks, destdir): |
572 | + for disk in disks: |
573 | + disk.convert(destdir, self.filetype) |
574 | + |
575 | + class NIC(object): |
576 | + def __init__(self, type='dhcp'): |
577 | + self.type = type |
578 | |
579 | === modified file 'VMBuilder/log.py' |
580 | --- VMBuilder/log.py 2009-06-10 13:40:41 +0000 |
581 | +++ VMBuilder/log.py 2010-02-18 16:03:14 +0000 |
582 | @@ -30,7 +30,7 @@ |
583 | logging.basicConfig(format=format, level=logging.DEBUG, datefmt='%Y-%m-%d %H:%M', stream=os.fdopen(fd, 'a+'), filemode='w') |
584 | |
585 | console = logging.StreamHandler() |
586 | -console.setLevel(logging.INFO) |
587 | +console.setLevel(logging.DEBUG) |
588 | console.setFormatter(logging.Formatter(format)) |
589 | logging.getLogger('').addHandler(console) |
590 | |
591 | |
592 | === modified file 'VMBuilder/plugins/__init__.py' |
593 | --- VMBuilder/plugins/__init__.py 2010-02-09 10:06:43 +0000 |
594 | +++ VMBuilder/plugins/__init__.py 2010-02-18 16:03:14 +0000 |
595 | @@ -20,7 +20,7 @@ |
596 | import re |
597 | |
598 | import VMBuilder |
599 | -from VMBuilder.util import run_cmd |
600 | +import VMBuilder.util as util |
601 | from VMBuilder.exception import VMBuilderException |
602 | |
603 | def load_plugins(): |
604 | @@ -39,8 +39,8 @@ |
605 | class Plugin(object): |
606 | priority = 10 |
607 | |
608 | - def __init__(self, vm): |
609 | - self.vm = vm |
610 | + def __init__(self, context): |
611 | + self.context = context |
612 | self._setting_groups = [] |
613 | self.register_options() |
614 | |
615 | @@ -64,31 +64,34 @@ |
616 | """ |
617 | pass |
618 | |
619 | - def deploy(self): |
620 | - """ |
621 | - Perform deployment of the VM. |
622 | - |
623 | - If True is returned, no further deployment will be done. |
624 | - """ |
625 | - return False |
626 | + def install_file(self, path, contents=None, source=None, mode=None): |
627 | + fullpath = '%s%s' % (self.chroot_dir, path) |
628 | + if source and not contents: |
629 | + shutil.copy(source, fullpath) |
630 | + else: |
631 | + fp = open(fullpath, 'w') |
632 | + fp.write(contents) |
633 | + fp.close() |
634 | + if mode: |
635 | + os.chmod(fullpath, mode) |
636 | + return fullpath |
637 | |
638 | def install_from_template(self, path, tmplname, context=None, mode=None): |
639 | - if not self.vm.fsmounted: |
640 | - raise VMBuilderException('install_from_template called while file system is not mounted') |
641 | - return self.vm.install_file(path, VMBuilder.util.render_template(self.__module__.split('.')[2], self.vm, tmplname, context), mode=mode) |
642 | + return self.install_file(path, VMBuilder.util.render_template(self.__module__.split('.')[2], self.context, tmplname, context), mode=mode) |
643 | |
644 | def run_in_target(self, *args, **kwargs): |
645 | - if not self.vm.fsmounted: |
646 | - raise VMBuilderException('install_from_template called while file system is not mounted') |
647 | - return run_cmd('chroot', self.vm.installdir, *args, **kwargs) |
648 | + return util.run_cmd('chroot', self.chroot_dir, *args, **kwargs) |
649 | + |
650 | + def call_hooks(self, *args, **kwargs): |
651 | + return util.call_hooks(self.context, *args, **kwargs) |
652 | |
653 | # Settings |
654 | class SettingGroup(object): |
655 | - def __init__(self, plugin, vm, name): |
656 | + def __init__(self, plugin, context, name): |
657 | # The plugin that owns this setting |
658 | self.plugin = plugin |
659 | # The VM object |
660 | - self.vm = vm |
661 | + self.context = context |
662 | # Name of the Setting Group |
663 | self.name = name |
664 | # A list of Setting objects |
665 | @@ -136,18 +139,19 @@ |
666 | self.help = help |
667 | # Alternate names (for the CLI) |
668 | self.extra_args = extra_args or [] |
669 | + self.metavar = metavar |
670 | self.value = None |
671 | self.value_set = False |
672 | self.valid_options = valid_options |
673 | |
674 | - if self.name in self.setting_group.vm._config: |
675 | + if self.name in self.setting_group.context._config: |
676 | raise VMBuilderException("Setting named %s already exists. Previous definition in %s/%s/%s." % |
677 | (self.name, |
678 | self.setting_group.plugin.__name__, |
679 | self.setting_group.plugin._config[self.name].setting_group.name, |
680 | self.setting_group.plugin._config[self.name].name)) |
681 | |
682 | - self.setting_group.vm._config[self.name] = self |
683 | + self.setting_group.context._config[self.name] = self |
684 | |
685 | def get_value(self): |
686 | """ |
687 | @@ -230,37 +234,40 @@ |
688 | raise VMBuilderException('%r is type %s, expected str.' % (value, type(value))) |
689 | |
690 | def setting_group(self, name): |
691 | - setting_group = self.SettingGroup(self, self.vm, name) |
692 | + setting_group = self.SettingGroup(self, self.context, name) |
693 | self._setting_groups.append(setting_group) |
694 | return setting_group |
695 | |
696 | + def has_setting(self, name): |
697 | + return name in self.context._config |
698 | + |
699 | def get_setting(self, name): |
700 | - if not name in self._config: |
701 | + if not name in self.context._config: |
702 | raise VMBuilderException('Unknown config key: %s' % name) |
703 | - return self._config[name].get_value() |
704 | + return self.context._config[name].get_value() |
705 | |
706 | def set_setting(self, name, value): |
707 | - if not name in self.vm._config: |
708 | + if not name in self.context._config: |
709 | raise VMBuilderException('Unknown config key: %s' % name) |
710 | - self._config[name].set_value(value) |
711 | + self.context._config[name].set_value(value) |
712 | |
713 | def set_setting_default(self, name, value): |
714 | - if not name in self.vm._config: |
715 | + if not name in self.context._config: |
716 | raise VMBuilderException('Unknown config key: %s' % name) |
717 | - self._config[name].set_default(value) |
718 | + self.context._config[name].set_default(value) |
719 | |
720 | def get_setting_default(self, name): |
721 | - if not name in self.vm._config: |
722 | + if not name in self.context._config: |
723 | raise VMBuilderException('Unknown config key: %s' % name) |
724 | - return self._config[name].get_default() |
725 | + return self.context._config[name].get_default() |
726 | |
727 | def get_setting_valid_options(self, name): |
728 | - if not name in self._config: |
729 | + if not name in self.context._config: |
730 | raise VMBuilderException('Unknown config key: %s' % name) |
731 | - return self._config[name].get_valid_options() |
732 | + return self.context._config[name].get_valid_options() |
733 | |
734 | def set_setting_valid_options(self, name, valid_options): |
735 | - if not name in self._config: |
736 | + if not name in self.context._config: |
737 | raise VMBuilderException('Unknown config key: %s' % name) |
738 | - self._config[name].set_valid_options(valid_options) |
739 | + self.context._config[name].set_valid_options(valid_options) |
740 | |
741 | |
742 | === modified file 'VMBuilder/plugins/cli/__init__.py' |
743 | --- VMBuilder/plugins/cli/__init__.py 2009-12-08 22:27:46 +0000 |
744 | +++ VMBuilder/plugins/cli/__init__.py 2010-02-18 16:03:14 +0000 |
745 | @@ -19,9 +19,12 @@ |
746 | from gettext import gettext |
747 | import logging |
748 | import optparse |
749 | +import os |
750 | +import pwd |
751 | import sys |
752 | import textwrap |
753 | import VMBuilder |
754 | +import VMBuilder.util as util |
755 | from VMBuilder.disk import parse_size |
756 | import VMBuilder.hypervisor |
757 | _ = gettext |
758 | @@ -31,89 +34,145 @@ |
759 | arg = 'cli' |
760 | |
761 | def run(self): |
762 | - try: |
763 | - next = False |
764 | - conf = None |
765 | - for val in sys.argv: |
766 | - if (val == '-c') | (val == '--config'): |
767 | - next = True |
768 | - elif next: |
769 | - conf = val |
770 | - break |
771 | - |
772 | - vm = VMBuilder.VM(conf) |
773 | - vm.register_setting('--version', action='callback', callback=self.versioninfo, callback_kwargs={ 'vm' : vm }, help='Show version information') |
774 | - vm.register_setting('--rootsize', metavar='SIZE', default=4096, help='Size (in MB) of the root filesystem [default: %default]') |
775 | - vm.register_setting('--optsize', metavar='SIZE', default=0, help='Size (in MB) of the /opt filesystem. If not set, no /opt filesystem will be added.') |
776 | - vm.register_setting('--swapsize', metavar='SIZE', default=1024, help='Size (in MB) of the swap partition [default: %default]') |
777 | - vm.register_setting('--raw', metavar='PATH', type='string', help="Specify a file (or block device) to as first disk image.") |
778 | - vm.register_setting('--part', metavar='PATH', type='string', help="Allows to specify a partition table in PATH each line of partfile should specify (root first): \n mountpoint size \none per line, separated by space, where size is in megabytes. You can have up to 4 virtual disks, a new disk starts on a line containing only '---'. ie: \n root 2000 \n /boot 512 \n swap 1000 \n --- \n /var 8000 \n /var/log 2000") |
779 | - self.set_usage(vm) |
780 | - |
781 | - vm.optparser.disable_interspersed_args() |
782 | - (foo, args) = vm.optparser.parse_args() |
783 | - self.handle_args(vm, args) |
784 | - vm.optparser.enable_interspersed_args() |
785 | - |
786 | - for opt in vm.optparser.option_list + sum([grp.option_list for grp in vm.optparser.option_groups], []): |
787 | - if len(opt._long_opts) > 1 or (opt.action == 'store' and opt._long_opts[0][2:] != opt.dest): |
788 | - opt.help += " Config option: %s" % opt.dest |
789 | - |
790 | - (settings, args) = vm.optparser.parse_args(values=optparse.Values()) |
791 | - for (k,v) in settings.__dict__.iteritems(): |
792 | - setattr(vm, k, v) |
793 | - |
794 | - self.set_disk_layout(vm) |
795 | - |
796 | - vm.create() |
797 | - except VMBuilder.VMBuilderUserError, e: |
798 | - print >> sys.stderr, e |
799 | - return(1) |
800 | - |
801 | - return(0) |
802 | - |
803 | - def versioninfo(self, option, opt, value, parser, vm=None): |
804 | - print '%(major)d.%(minor)d.%(micro).r%(revno)d' % vm.get_version_info() |
805 | + |
806 | + if len(sys.argv) < 3: |
807 | + print 'Usage: %s hypervisor distro [options]' % sys.argv[0] |
808 | + sys.exit(1) |
809 | + |
810 | + group = self.setting_group(' ') |
811 | + group.add_setting('config', extra_args=['-c'], type='str', help='Configuration file') |
812 | + group.add_setting('destdir', extra_args=['-d'], type='str', help='Destination directory') |
813 | + |
814 | + group = self.setting_group('Disk') |
815 | + group.add_setting('rootsize', metavar='SIZE', default=4096, help='Size (in MB) of the root filesystem [default: %default]') |
816 | + group.add_setting('optsize', metavar='SIZE', default=0, help='Size (in MB) of the /opt filesystem. If not set, no /opt filesystem will be added.') |
817 | + group.add_setting('swapsize', metavar='SIZE', default=1024, help='Size (in MB) of the swap partition [default: %default]') |
818 | + group.add_setting('raw', metavar='PATH', type='str', help="Specify a file (or block device) to as first disk image.") |
819 | + group.add_setting('part', metavar='PATH', type='str', help="Allows to specify a partition table in PATH each line of partfile should specify (root first): \n mountpoint size \none per line, separated by space, where size is in megabytes. You can have up to 4 virtual disks, a new disk starts on a line containing only '---'. ie: \n root 2000 \n /boot 512 \n swap 1000 \n --- \n /var 8000 \n /var/log 2000") |
820 | + |
821 | + optparser = optparse.OptionParser() |
822 | + optparser.add_option('--version', action='callback', callback=self.versioninfo, help='Show version information') |
823 | + distro_name = sys.argv[2] |
824 | + distro_class = VMBuilder.get_distro(distro_name) |
825 | + distro = distro_class() |
826 | + distro.plugins.append(self) |
827 | + self.add_settings_from_context(optparser, distro) |
828 | + |
829 | + hypervisor_name = sys.argv[1] |
830 | + hypervisor_class = VMBuilder.get_hypervisor(hypervisor_name) |
831 | + hypervisor = hypervisor_class(distro) |
832 | + hypervisor.plugins.append(self) |
833 | + self.add_settings_from_context(optparser, hypervisor) |
834 | + |
835 | + self.set_setting_default('destdir', '%s-%s' % (distro_name, hypervisor_name)) |
836 | + |
837 | + (options, args) = optparser.parse_args(sys.argv[2:]) |
838 | + for option in dir(options): |
839 | + if option.startswith('_') or option in ['ensure_value', 'read_module', 'read_file']: |
840 | + continue |
841 | + val = getattr(options, option) |
842 | + if val: |
843 | + if distro.has_setting(option): |
844 | + distro.set_setting(option, val) |
845 | + else: |
846 | + hypervisor.set_setting(option, val) |
847 | + |
848 | + chroot_dir = util.tmpdir() |
849 | + |
850 | + distro.set_chroot_dir(chroot_dir) |
851 | + distro.build_chroot() |
852 | + |
853 | + self.set_disk_layout(hypervisor) |
854 | + hypervisor.install_os() |
855 | + |
856 | + destdir = self.get_setting('destdir') |
857 | + os.mkdir(destdir) |
858 | + self.fix_ownership(destdir) |
859 | + hypervisor.finalise(destdir) |
860 | + |
861 | + sys.exit(1) |
862 | + |
863 | + def fix_ownership(self, filename): |
864 | + """ |
865 | + Change ownership of file to $SUDO_USER. |
866 | + |
867 | + @type path: string |
868 | + @param path: file or directory to give to $SUDO_USER |
869 | + """ |
870 | + |
871 | + if 'SUDO_USER' in os.environ: |
872 | + logging.debug('Changing ownership of %s to %s' % (filename, os.environ['SUDO_USER'])) |
873 | + (uid, gid) = pwd.getpwnam(os.environ['SUDO_USER'])[2:4] |
874 | + os.chown(filename, uid, gid) |
875 | + |
876 | + def add_settings_from_context(self, optparser, context): |
877 | + setting_groups = set([setting.setting_group for setting in context._config.values()]) |
878 | + for setting_group in setting_groups: |
879 | + optgroup = optparse.OptionGroup(optparser, setting_group.name) |
880 | + for setting in setting_group._settings: |
881 | + args = ['--%s' % setting.name] |
882 | + args += setting.extra_args |
883 | + kwargs = {} |
884 | + if setting.help: |
885 | + kwargs['help'] = setting.help |
886 | + if len(setting.extra_args) > 0: |
887 | + setting.help += " Config option: %s" % setting.name |
888 | + if setting.metavar: |
889 | + kwargs['metavar'] = setting.metavar |
890 | + if setting.get_default(): |
891 | + kwargs['default'] = setting.get_default() |
892 | + if type(setting) == VMBuilder.plugins.Plugin.BooleanSetting: |
893 | + kwargs['action'] = 'store_true' |
894 | + if type(setting) == VMBuilder.plugins.Plugin.ListSetting: |
895 | + kwargs['action'] = 'append' |
896 | + optgroup.add_option(*args, **kwargs) |
897 | + optparser.add_option_group(optgroup) |
898 | + |
899 | + def versioninfo(self, option, opt, value, parser): |
900 | + print '%(major)d.%(minor)d.%(micro)s.r%(revno)d' % VMBuilder.get_version_info() |
901 | sys.exit(0) |
902 | |
903 | - def set_usage(self, vm): |
904 | - vm.optparser.set_usage('%prog hypervisor distro [options]') |
905 | - vm.optparser.arg_help = (('hypervisor', vm.hypervisor_help), ('distro', vm.distro_help)) |
906 | + def set_usage(self, optparser): |
907 | + optparser.set_usage('%prog hypervisor distro [options]') |
908 | + optparser.arg_help = (('hypervisor', vm.hypervisor_help), ('distro', vm.distro_help)) |
909 | |
910 | def handle_args(self, vm, args): |
911 | if len(args) < 2: |
912 | vm.optparser.error("You need to specify at least the hypervisor type and the distro") |
913 | - vm.set_hypervisor(args[0]) |
914 | - vm.set_distro(args[1]) |
915 | + self.hypervisor = vm.get_hypervisor(args[0]) |
916 | + self.distro = distro.vm.get_distro(args[1]) |
917 | |
918 | - def set_disk_layout(self, vm): |
919 | - if not vm.part: |
920 | - vm.rootsize = parse_size(vm.rootsize) |
921 | - vm.swapsize = parse_size(vm.swapsize) |
922 | - vm.optsize = parse_size(vm.optsize) |
923 | - if vm.hypervisor.preferred_storage == VMBuilder.hypervisor.STORAGE_FS_IMAGE: |
924 | - vm.add_filesystem(size='%dM' % vm.rootsize, type='ext3', mntpnt='/') |
925 | - vm.add_filesystem(size='%dM' % vm.swapsize, type='swap', mntpnt=None) |
926 | - if vm.optsize > 0: |
927 | - vm.add_filesystem(size='%dM' % optsize, type='ext3', mntpnt='/opt') |
928 | + def set_disk_layout(self, hypervisor): |
929 | + if not self.get_setting('part'): |
930 | + rootsize = parse_size(self.get_setting('rootsize')) |
931 | + swapsize = parse_size(self.get_setting('swapsize')) |
932 | + optsize = parse_size(self.get_setting('optsize')) |
933 | + if hypervisor.preferred_storage == VMBuilder.hypervisor.STORAGE_FS_IMAGE: |
934 | + hypervisor.add_filesystem(size='%dM' % rootsize, type='ext3', mntpnt='/') |
935 | + hypervisor.add_filesystem(size='%dM' % swapsize, type='swap', mntpnt=None) |
936 | + if optsize > 0: |
937 | + hypervisor.add_filesystem(size='%dM' % optsize, type='ext3', mntpnt='/opt') |
938 | else: |
939 | - if vm.raw: |
940 | - disk = vm.add_disk(filename=vm.raw, preallocated=True) |
941 | + raw = self.get_setting('raw') |
942 | + if raw: |
943 | + disk = hypervisor.add_disk(filename=raw, preallocated=True) |
944 | else: |
945 | - size = vm.rootsize + vm.swapsize + vm.optsize |
946 | - disk = vm.add_disk(size='%dM' % size) |
947 | + size = rootsize + swapsize + optsize |
948 | + tmpfile = util.tmpfile(keep=False) |
949 | + disk = hypervisor.add_disk(tmpfile, size='%dM' % size) |
950 | offset = 0 |
951 | - disk.add_part(offset, vm.rootsize, 'ext3', '/') |
952 | - offset += vm.rootsize |
953 | - disk.add_part(offset, vm.swapsize, 'swap', 'swap') |
954 | - offset += vm.swapsize |
955 | - if vm.optsize > 0: |
956 | - disk.add_part(offset, vm.optsize, 'ext3', '/opt') |
957 | + disk.add_part(offset, rootsize, 'ext3', '/') |
958 | + offset += rootsize |
959 | + disk.add_part(offset, swapsize, 'swap', 'swap') |
960 | + offset += swapsize |
961 | + if optsize > 0: |
962 | + disk.add_part(offset, optsize, 'ext3', '/opt') |
963 | else: |
964 | # We need to parse the file specified |
965 | + part = self.get_setting('part') |
966 | if vm.hypervisor.preferred_storage == VMBuilder.hypervisor.STORAGE_FS_IMAGE: |
967 | try: |
968 | - for line in file(vm.part): |
969 | + for line in file(part): |
970 | elements = line.strip().split(' ') |
971 | if elements[0] == 'root': |
972 | vm.add_filesystem(elements[1], type='ext3', mntpnt='/') |
973 | @@ -133,7 +192,7 @@ |
974 | try: |
975 | curdisk = list() |
976 | size = 0 |
977 | - for line in file(vm.part): |
978 | + for line in file(part): |
979 | pair = line.strip().split(' ',1) |
980 | if pair[0] == '---': |
981 | self.do_disk(vm, curdisk, size) |
982 | @@ -167,8 +226,8 @@ |
983 | arg = 'ubuntu-vm-builder' |
984 | |
985 | def set_usage(self, vm): |
986 | - vm.optparser.set_usage('%prog hypervisor suite [options]') |
987 | - vm.optparser.arg_help = (('hypervisor', vm.hypervisor_help), ('suite', self.suite_help)) |
988 | + optparser.set_usage('%prog hypervisor suite [options]') |
989 | + optparser.arg_help = (('hypervisor', vm.hypervisor_help), ('suite', self.suite_help)) |
990 | |
991 | def suite_help(self): |
992 | return 'Suite. Valid options: %s' % " ".join(VMBuilder.plugins.ubuntu.distro.Ubuntu.suites) |
993 | |
994 | === modified file 'VMBuilder/plugins/ec2/__init__.py' |
995 | --- VMBuilder/plugins/ec2/__init__.py 2009-07-07 11:14:54 +0000 |
996 | +++ VMBuilder/plugins/ec2/__init__.py 2010-02-18 16:03:14 +0000 |
997 | @@ -17,7 +17,7 @@ |
998 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
999 | # |
1000 | import VMBuilder |
1001 | -from VMBuilder import register_plugin, Plugin, VMBuilderUserError, VMBuilderException |
1002 | +from VMBuilder import register_distro_plugin, register_hypervisor_plugin, Plugin, VMBuilderUserError, VMBuilderException |
1003 | from VMBuilder.util import run_cmd |
1004 | import logging |
1005 | import os |
1006 | @@ -27,9 +27,9 @@ |
1007 | |
1008 | def register_options(self): |
1009 | # Don't pretend like we can do EC2 |
1010 | - if not isinstance(self.vm.hypervisor, VMBuilder.plugins.xen.Xen): |
1011 | + if not isinstance(self.context.hypervisor, VMBuilder.plugins.xen.Xen): |
1012 | return |
1013 | - group = self.vm.setting_group('EC2 integation') |
1014 | + group = self.context.setting_group('EC2 integation') |
1015 | group.add_option('--ec2', action='store_true', help='Build for EC2') |
1016 | group.add_option('--ec2-name','--ec2-prefix', metavar='EC2_NAME', help='Name for the EC2 image.') |
1017 | group.add_option('--ec2-cert', metavar='CERTFILE', help='PEM encoded public certificate for EC2.') |
1018 | @@ -45,106 +45,106 @@ |
1019 | group.add_option('--ec2-bundle', action='store_true', help='Bundle the instance') |
1020 | group.add_option('--ec2-upload', action='store_true', help='Upload the instance') |
1021 | group.add_option('--ec2-register', action='store_true', help='Register the instance') |
1022 | - self.vm.register_setting_group(group) |
1023 | + self.context.register_setting_group(group) |
1024 | |
1025 | def preflight_check(self): |
1026 | if not getattr(self.vm, 'ec2', False): |
1027 | return True |
1028 | |
1029 | - if not self.vm.hypervisor.name == 'Xen': |
1030 | + if not self.context.hypervisor.name == 'Xen': |
1031 | raise VMBuilderUserError('When building for EC2 you must use the xen hypervisor.') |
1032 | |
1033 | - if self.vm.ec2_bundle: |
1034 | + if self.context.ec2_bundle: |
1035 | try: |
1036 | run_cmd('ec2-ami-tools-version') |
1037 | except VMBuilderException, e: |
1038 | raise VMBuilderUserError('You need to have the Amazon EC2 AMI tools installed') |
1039 | |
1040 | - if not self.vm.ec2_name: |
1041 | + if not self.context.ec2_name: |
1042 | raise VMBuilderUserError('When building for EC2 you must supply the name for the image.') |
1043 | |
1044 | - if not self.vm.ec2_cert: |
1045 | + if not self.context.ec2_cert: |
1046 | if "EC2_CERT" in os.environ: |
1047 | - self.vm.ec2_cert = os.environ["EC2_CERT"] |
1048 | + self.context.ec2_cert = os.environ["EC2_CERT"] |
1049 | else: |
1050 | raise VMBuilderUserError('When building for EC2 you must provide your PEM encoded public key certificate') |
1051 | |
1052 | - if not self.vm.ec2_key: |
1053 | + if not self.context.ec2_key: |
1054 | if "EC2_PRIVATE_KEY" in os.environ: |
1055 | - self.vm.ec2_key = os.environ["EC2_PRIVATE_KEY"] |
1056 | + self.context.ec2_key = os.environ["EC2_PRIVATE_KEY"] |
1057 | else: |
1058 | raise VMBuilderUserError('When building for EC2 you must provide your PEM encoded private key file') |
1059 | |
1060 | - if not self.vm.ec2_user: |
1061 | + if not self.context.ec2_user: |
1062 | raise VMBuilderUserError('When building for EC2 you must provide your EC2 user ID (your AWS account number, not your AWS access key ID)') |
1063 | |
1064 | - if not self.vm.ec2_kernel: |
1065 | - self.vm.ec2_kernel = self.vm.distro.get_ec2_kernel() |
1066 | - logging.debug('%s - to be used for AKI.' %(self.vm.ec2_kernel)) |
1067 | - |
1068 | - if not self.vm.ec2_ramdisk: |
1069 | - self.vm.ec2_ramdisk = self.vm.distro.ec2_ramdisk_id() |
1070 | - logging.debug('%s - to be use for the ARI.' %(self.vm.ec2_ramdisk)) |
1071 | - |
1072 | - if self.vm.ec2_upload: |
1073 | - if not self.vm.ec2_bucket: |
1074 | + if not self.context.ec2_kernel: |
1075 | + self.context.ec2_kernel = self.vm.distro.get_ec2_kernel() |
1076 | + logging.debug('%s - to be used for AKI.' %(self.context.ec2_kernel)) |
1077 | + |
1078 | + if not self.context.ec2_ramdisk: |
1079 | + self.context.ec2_ramdisk = self.vm.distro.ec2_ramdisk_id() |
1080 | + logging.debug('%s - to be use for the ARI.' %(self.context.ec2_ramdisk)) |
1081 | + |
1082 | + if self.context.ec2_upload: |
1083 | + if not self.context.ec2_bucket: |
1084 | raise VMBuilderUserError('When building for EC2 you must provide an S3 bucket to hold the AMI') |
1085 | |
1086 | - if not self.vm.ec2_access_key: |
1087 | + if not self.context.ec2_access_key: |
1088 | raise VMBuilderUserError('When building for EC2 you must provide your AWS access key ID.') |
1089 | |
1090 | - if not self.vm.ec2_secret_key: |
1091 | + if not self.context.ec2_secret_key: |
1092 | raise VMBuilderUserError('When building for EC2 you must provide your AWS secret access key.') |
1093 | |
1094 | - if not self.vm.ec2_version: |
1095 | + if not self.context.ec2_version: |
1096 | raise VMBuilderUserError('When building for EC2 you must provide version info.') |
1097 | |
1098 | - if not self.vm.addpkg: |
1099 | - self.vm.addpkg = [] |
1100 | + if not self.context.addpkg: |
1101 | + self.context.addpkg = [] |
1102 | |
1103 | - if self.vm.ec2_landscape: |
1104 | + if self.context.ec2_landscape: |
1105 | logging.info('Installing landscape support') |
1106 | - self.vm.addpkg += ['landscape-client'] |
1107 | + self.context.addpkg += ['landscape-client'] |
1108 | |
1109 | def post_install(self): |
1110 | if not getattr(self.vm, 'ec2', False): |
1111 | return |
1112 | |
1113 | logging.info("Running ec2 postinstall") |
1114 | - self.install_from_template('/etc/ec2_version', 'ec2_version', { 'version' : self.vm.ec2_version } ) |
1115 | + self.install_from_template('/etc/ec2_version', 'ec2_version', { 'version' : self.context.ec2_version } ) |
1116 | self.install_from_template('/etc/ssh/sshd_config', 'sshd_config') |
1117 | self.install_from_template('/etc/sudoers', 'sudoers') |
1118 | |
1119 | - if self.vm.ec2_landscape: |
1120 | + if self.context.ec2_landscape: |
1121 | self.install_from_template('/etc/default/landscape-client', 'landscape_client') |
1122 | |
1123 | - self.vm.distro.disable_hwclock_access() |
1124 | + self.context.distro.disable_hwclock_access() |
1125 | |
1126 | def deploy(self): |
1127 | if not getattr(self.vm, 'ec2', False): |
1128 | return False |
1129 | |
1130 | - if self.vm.ec2_bundle: |
1131 | + if self.context.ec2_bundle: |
1132 | logging.info("Building EC2 bundle") |
1133 | - bundle_cmdline = ['ec2-bundle-image', '--image', self.vm.filesystems[0].filename, '--cert', self.vm.ec2_cert, '--privatekey', self.vm.ec2_key, '--user', self.vm.ec2_user, '--prefix', self.vm.ec2_name, '-r', ['i386', 'x86_64'][self.vm.arch == 'amd64'], '-d', self.vm.workdir, '--kernel', self.vm.ec2_kernel, '--ramdisk', self.vm.ec2_ramdisk] |
1134 | + bundle_cmdline = ['ec2-bundle-image', '--image', self.context.filesystems[0].filename, '--cert', self.vm.ec2_cert, '--privatekey', self.vm.ec2_key, '--user', self.vm.ec2_user, '--prefix', self.vm.ec2_name, '-r', ['i386', 'x86_64'][self.vm.arch == 'amd64'], '-d', self.vm.workdir, '--kernel', self.vm.ec2_kernel, '--ramdisk', self.vm.ec2_ramdisk] |
1135 | run_cmd(*bundle_cmdline) |
1136 | |
1137 | - manifest = '%s/%s.manifest.xml' % (self.vm.workdir, self.vm.ec2_name) |
1138 | - if self.vm.ec2_upload: |
1139 | + manifest = '%s/%s.manifest.xml' % (self.context.workdir, self.vm.ec2_name) |
1140 | + if self.context.ec2_upload: |
1141 | logging.info("Uploading EC2 bundle") |
1142 | - upload_cmdline = ['ec2-upload-bundle', '--retry', '--manifest', manifest, '--bucket', self.vm.ec2_bucket, '--access-key', self.vm.ec2_access_key, '--secret-key', self.vm.ec2_secret_key] |
1143 | + upload_cmdline = ['ec2-upload-bundle', '--retry', '--manifest', manifest, '--bucket', self.context.ec2_bucket, '--access-key', self.vm.ec2_access_key, '--secret-key', self.vm.ec2_secret_key] |
1144 | run_cmd(*upload_cmdline) |
1145 | |
1146 | - if self.vm.ec2_register: |
1147 | + if self.context.ec2_register: |
1148 | from boto.ec2.connection import EC2Connection |
1149 | - conn = EC2Connection(self.vm.ec2_access_key, self.vm.ec2_secret_key) |
1150 | - amiid = conn.register_image('%s/%s.manifest.xml' % (self.vm.ec2_bucket, self.vm.ec2_name)) |
1151 | + conn = EC2Connection(self.context.ec2_access_key, self.vm.ec2_secret_key) |
1152 | + amiid = conn.register_image('%s/%s.manifest.xml' % (self.context.ec2_bucket, self.vm.ec2_name)) |
1153 | print 'Image registered as %s' % amiid |
1154 | else: |
1155 | - self.vm.result_files.append(manifest) |
1156 | + self.context.result_files.append(manifest) |
1157 | else: |
1158 | - self.vm.result_files.append(self.vm.filesystems[0].filename) |
1159 | + self.context.result_files.append(self.vm.filesystems[0].filename) |
1160 | |
1161 | return True |
1162 | |
1163 | -register_plugin(EC2) |
1164 | +#register_plugin(EC2) |
1165 | |
1166 | === modified file 'VMBuilder/plugins/firstscripts/__init__.py' |
1167 | --- VMBuilder/plugins/firstscripts/__init__.py 2009-06-10 13:40:41 +0000 |
1168 | +++ VMBuilder/plugins/firstscripts/__init__.py 2010-02-18 16:03:14 +0000 |
1169 | @@ -16,7 +16,7 @@ |
1170 | # You should have received a copy of the GNU General Public License |
1171 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
1172 | # |
1173 | -from VMBuilder import register_plugin, Plugin, VMBuilderUserError |
1174 | +from VMBuilder import register_distro_plugin, Plugin, VMBuilderUserError |
1175 | from VMBuilder.util import run_cmd |
1176 | |
1177 | import logging |
1178 | @@ -31,36 +31,36 @@ |
1179 | name = 'First-Scripts plugin' |
1180 | |
1181 | def register_options(self): |
1182 | - group = self.vm.setting_group('Scripts') |
1183 | + group = self.context.setting_group('Scripts') |
1184 | group.add_option('--firstboot', metavar='PATH', default='', help='Specify a script that will be copied into the guest and executed the first time the machine boots. This script must not be interactive.') |
1185 | group.add_option('--firstlogin', metavar='PATH', default='', help='Specify a script that will be copied into the guest and will be executed the first time the user logs in. This script can be interactive.') |
1186 | - self.vm.register_setting_group(group) |
1187 | + self.context.register_setting_group(group) |
1188 | |
1189 | def preflight_check(self): |
1190 | |
1191 | - if self.vm.firstboot: |
1192 | - logging.debug("Checking if firstboot script %s exists" % (self.vm.firstboot,)) |
1193 | - if not(os.path.isfile(self.vm.firstboot)): |
1194 | - raise VMBuilderUserError('The path to the first-boot script is invalid: %s. Make sure you are providing a full path.' % self.vm.firstboot) |
1195 | + if self.context.firstboot: |
1196 | + logging.debug("Checking if firstboot script %s exists" % (self.context.firstboot,)) |
1197 | + if not(os.path.isfile(self.context.firstboot)): |
1198 | + raise VMBuilderUserError('The path to the first-boot script is invalid: %s. Make sure you are providing a full path.' % self.context.firstboot) |
1199 | |
1200 | - if self.vm.firstlogin: |
1201 | - logging.debug("Checking if first login script %s exists" % (self.vm.firstlogin,)) |
1202 | - if not(os.path.isfile(self.vm.firstlogin)): |
1203 | - raise VMBuilderUserError('The path to the first-login script is invalid: %s. Make sure you are providing a full path.' % self.vm.firstlogin) |
1204 | + if self.context.firstlogin: |
1205 | + logging.debug("Checking if first login script %s exists" % (self.context.firstlogin,)) |
1206 | + if not(os.path.isfile(self.context.firstlogin)): |
1207 | + raise VMBuilderUserError('The path to the first-login script is invalid: %s. Make sure you are providing a full path.' % self.context.firstlogin) |
1208 | |
1209 | def post_install(self): |
1210 | - logging.debug("Installing firstboot script %s" % (self.vm.firstboot,)) |
1211 | - if self.vm.firstboot: |
1212 | - self.vm.install_file('/root/firstboot.sh', source=self.vm.firstboot, mode=0700) |
1213 | - os.rename('%s/etc/rc.local' % self.vm.installdir, '%s/etc/rc.local.orig' % self.vm.installdir) |
1214 | + logging.debug("Installing firstboot script %s" % (self.context.firstboot,)) |
1215 | + if self.context.firstboot: |
1216 | + self.context.install_file('/root/firstboot.sh', source=self.vm.firstboot, mode=0700) |
1217 | + os.rename('%s/etc/rc.local' % self.context.installdir, '%s/etc/rc.local.orig' % self.vm.installdir) |
1218 | self.install_from_template('/etc/rc.local', 'firstbootrc', mode=0755) |
1219 | |
1220 | - logging.debug("Installing first login script %s" % (self.vm.firstlogin,)) |
1221 | - if self.vm.firstlogin: |
1222 | - self.vm.install_file('/root/firstlogin.sh', source=self.vm.firstlogin, mode=0755) |
1223 | - os.rename('%s/etc/bash.bashrc' % self.vm.installdir, '%s/etc/bash.bashrc.orig' % self.vm.installdir) |
1224 | + logging.debug("Installing first login script %s" % (self.context.firstlogin,)) |
1225 | + if self.context.firstlogin: |
1226 | + self.context.install_file('/root/firstlogin.sh', source=self.vm.firstlogin, mode=0755) |
1227 | + os.rename('%s/etc/bash.bashrc' % self.context.installdir, '%s/etc/bash.bashrc.orig' % self.vm.installdir) |
1228 | self.install_from_template('/etc/bash.bashrc', 'firstloginrc') |
1229 | |
1230 | return True |
1231 | |
1232 | -register_plugin(Firstscripts) |
1233 | +#register_plugin(Firstscripts) |
1234 | |
1235 | === modified file 'VMBuilder/plugins/kvm/vm.py' |
1236 | --- VMBuilder/plugins/kvm/vm.py 2009-06-10 13:40:41 +0000 |
1237 | +++ VMBuilder/plugins/kvm/vm.py 2010-02-18 16:03:14 +0000 |
1238 | @@ -30,24 +30,28 @@ |
1239 | preferred_storage = VMBuilder.hypervisor.STORAGE_DISK_IMAGE |
1240 | needs_bootloader = True |
1241 | |
1242 | - def finalize(self): |
1243 | + def register_options(self): |
1244 | + group = self.setting_group('VM settings') |
1245 | + group.add_setting('mem', extra_args=['-m'], default='128', help='Assign MEM megabytes of memory to the guest vm. [default: %default]') |
1246 | + group.add_setting('cpus', type='int', default=1, help='Number of virtual CPU\'s. [default: %default]') |
1247 | + |
1248 | + def convert(self, disks, destdir): |
1249 | self.imgs = [] |
1250 | - self.cmdline = ['kvm', '-m', str(self.vm.mem), '-smp', str(self.vm.cpus) ] |
1251 | - for disk in self.vm.disks: |
1252 | - img_path = disk.convert(self.vm.destdir, self.filetype) |
1253 | + self.cmdline = ['kvm', '-m', str(self.context.get_setting('mem')), '-smp', str(self.context.get_setting('cpus')) ] |
1254 | + for disk in disks: |
1255 | + img_path = disk.convert(destdir, self.filetype) |
1256 | self.imgs.append(img_path) |
1257 | - self.vm.result_files.append(img_path) |
1258 | + self.call_hooks('fix_ownership', img_path) |
1259 | self.cmdline += ['-drive', 'file=%s' % os.path.basename(img_path)] |
1260 | - |
1261 | |
1262 | self.cmdline += ['"$@"'] |
1263 | |
1264 | - def deploy(self): |
1265 | - script = '%s/run.sh' % self.vm.destdir |
1266 | + def deploy(self, destdir): |
1267 | + script = '%s/run.sh' % destdir |
1268 | fp = open(script, 'w') |
1269 | fp.write("#!/bin/sh\n\nexec %s\n" % ' '.join(self.cmdline)) |
1270 | fp.close() |
1271 | os.chmod(script, stat.S_IRWXU | stat.S_IRWXU | stat.S_IROTH | stat.S_IXOTH) |
1272 | - self.vm.result_files.append(script) |
1273 | + self.call_hooks('fix_ownership', script) |
1274 | |
1275 | register_hypervisor(KVM) |
1276 | |
1277 | === modified file 'VMBuilder/plugins/libvirt/__init__.py' |
1278 | --- VMBuilder/plugins/libvirt/__init__.py 2009-06-10 13:40:41 +0000 |
1279 | +++ VMBuilder/plugins/libvirt/__init__.py 2010-02-18 16:03:14 +0000 |
1280 | @@ -16,53 +16,53 @@ |
1281 | # You should have received a copy of the GNU General Public License |
1282 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
1283 | # |
1284 | -from VMBuilder import register_plugin, Plugin, VMBuilderUserError |
1285 | +from VMBuilder import register_hypervisor_plugin, Plugin, VMBuilderUserError |
1286 | import VMBuilder.util |
1287 | |
1288 | class Libvirt(Plugin): |
1289 | name = 'libvirt integration' |
1290 | |
1291 | def register_options(self): |
1292 | - group = self.vm.setting_group('libvirt integration') |
1293 | + group = self.context.setting_group('libvirt integration') |
1294 | group.add_option('--libvirt', metavar='URI', help='Add VM to given URI') |
1295 | group.add_option('--bridge', metavar="BRIDGE", help='Set up bridged network connected to BRIDGE.') |
1296 | - self.vm.register_setting_group(group) |
1297 | + self.context.register_setting_group(group) |
1298 | |
1299 | def all_domains(self): |
1300 | # This does not seem to work when any domain is already running |
1301 | return self.conn.listDefinedDomains() + [self.conn.lookupByID(id).name() for id in self.conn.listDomainsID()] |
1302 | |
1303 | def preflight_check(self): |
1304 | - if not self.vm.libvirt: |
1305 | + if not self.context.libvirt: |
1306 | return True |
1307 | |
1308 | import libvirt |
1309 | |
1310 | - self.conn = libvirt.open(self.vm.libvirt) |
1311 | - if self.vm.hostname in self.all_domains() and not self.vm.overwrite: |
1312 | - raise VMBuilderUserError('Domain %s already exists at %s' % (self.vm.hostname, self.vm.libvirt)) |
1313 | + self.conn = libvirt.open(self.context.libvirt) |
1314 | + if self.context.hostname in self.all_domains() and not self.vm.overwrite: |
1315 | + raise VMBuilderUserError('Domain %s already exists at %s' % (self.context.hostname, self.vm.libvirt)) |
1316 | |
1317 | - if not self.vm.hypervisor.name == 'KVM': |
1318 | + if not self.context.hypervisor.name == 'KVM': |
1319 | raise VMBuilderUserError('The libvirt plugin is only equiped to work with KVM at the moment.') |
1320 | |
1321 | - if not self.vm.hypervisor.name == 'KVM': |
1322 | + if not self.context.hypervisor.name == 'KVM': |
1323 | raise VMBuilderUserError('The libvirt plugin is only equiped to work with KVM at the moment.') |
1324 | |
1325 | def deploy(self): |
1326 | - if not self.vm.libvirt: |
1327 | + if not self.context.libvirt: |
1328 | # Not for us |
1329 | return False |
1330 | |
1331 | - if self.vm.hypervisor.preferred_storage == VMBuilder.hypervisor.STORAGE_FS_IMAGE: |
1332 | + if self.context.hypervisor.preferred_storage == VMBuilder.hypervisor.STORAGE_FS_IMAGE: |
1333 | vmxml = VMBuilder.util.render_template('libvirt', self.vm, 'libvirtxml_fsimage') |
1334 | else: |
1335 | vmxml = VMBuilder.util.render_template('libvirt', self.vm, 'libvirtxml') |
1336 | |
1337 | - if self.vm.hostname in self.all_domains() and not self.vm.overwrite: |
1338 | - raise VMBuilderUserError('Domain %s already exists at %s' % (self.vm.hostname, self.vm.libvirt)) |
1339 | + if self.context.hostname in self.all_domains() and not self.vm.overwrite: |
1340 | + raise VMBuilderUserError('Domain %s already exists at %s' % (self.context.hostname, self.vm.libvirt)) |
1341 | else: |
1342 | self.conn.defineXML(vmxml) |
1343 | |
1344 | return True |
1345 | |
1346 | -register_plugin(Libvirt) |
1347 | +#register_plugin(Libvirt) |
1348 | |
1349 | === modified file 'VMBuilder/plugins/network/__init__.py' |
1350 | --- VMBuilder/plugins/network/__init__.py 2010-02-02 15:36:35 +0000 |
1351 | +++ VMBuilder/plugins/network/__init__.py 2010-02-18 16:03:14 +0000 |
1352 | @@ -23,7 +23,7 @@ |
1353 | import struct |
1354 | import socket |
1355 | |
1356 | -from VMBuilder import register_plugin |
1357 | +from VMBuilder import register_hypervisor_plugin, register_distro_plugin |
1358 | from VMBuilder.plugins import Plugin |
1359 | from VMBuilder.exception import VMBuilderUserError |
1360 | |
1361 | @@ -64,52 +64,80 @@ |
1362 | def guess_gw_from_ip(ip): |
1363 | return ip + 0x01000000 |
1364 | |
1365 | -class NetworkPlugin(Plugin): |
1366 | +class NetworkDistroPlugin(Plugin): |
1367 | + def register_options(self): |
1368 | + group = self.setting_group('Network') |
1369 | + domainname = '.'.join(socket.gethostbyname_ex(socket.gethostname())[0].split('.')[1:]) or "defaultdomain" |
1370 | + group.add_setting('domain', metavar='DOMAIN', default=domainname, help='Set DOMAIN as the domain name of the guest [default: %default].') |
1371 | + |
1372 | + def preflight_check(self): |
1373 | + domain = self.context.get_setting('domain') |
1374 | + if domain == '': |
1375 | + raise VMBuilderUserError('Domain is undefined and host has no domain set.') |
1376 | + |
1377 | +class NetworkHypervisorPlugin(Plugin): |
1378 | + def register_options(self): |
1379 | + group = self.setting_group('Network') |
1380 | + group.add_setting('ip', metavar='ADDRESS', default='dhcp', help='IP address in dotted form [default: %default].') |
1381 | + group.add_setting('mac', metavar='MAC', help='MAC address of the guest [default: random].') |
1382 | + group.add_setting('mask', metavar='VALUE', help='IP mask in dotted form [default: based on ip setting]. Ignored if ip is not specified.') |
1383 | + group.add_setting('net', metavar='ADDRESS', help='IP net address in dotted form [default: based on ip setting]. Ignored if ip is not specified.') |
1384 | + group.add_setting('bcast', metavar='VALUE', help='IP broadcast in dotted form [default: based on ip setting]. Ignored if ip is not specified.') |
1385 | + group.add_setting('gw', metavar='ADDRESS', help='Gateway (router) address in dotted form [default: based on ip setting (first valid address in the network)]. Ignored if ip is not specified.') |
1386 | + group.add_setting('dns', metavar='ADDRESS', help='DNS address in dotted form [default: based on ip setting (first valid address in the network)] Ignored if ip is not specified.') |
1387 | + |
1388 | + |
1389 | def preflight_check(self): |
1390 | """ |
1391 | Validate the ip configuration given and set defaults |
1392 | """ |
1393 | |
1394 | - logging.debug("ip: %s" % self.vm.ip) |
1395 | + ip = self.context.get_setting('ip') |
1396 | + logging.debug("ip: %s" % ip) |
1397 | |
1398 | - if self.vm.mac: |
1399 | + mac = self.context.get_setting('mac') |
1400 | + if mac: |
1401 | if not validate_mac(mac): |
1402 | raise VMBuilderUserError("Malformed MAC address entered: %s" % mac) |
1403 | |
1404 | - if self.vm.ip != 'dhcp': |
1405 | - if self.vm.domain == '': |
1406 | - raise VMBuilderUserError('Domain is undefined and host has no domain set.') |
1407 | - |
1408 | + if ip != 'dhcp': |
1409 | # num* are numeric representations |
1410 | - numip = dotted_to_numeric_ip(self.vm.ip) |
1411 | + numip = dotted_to_numeric_ip(ip) |
1412 | |
1413 | - if not self.vm.mask: |
1414 | + mask = self.context.get_setting('mask') |
1415 | + if not mask: |
1416 | nummask = guess_mask_from_ip(numip) |
1417 | else: |
1418 | - nummask = dotted_to_numeric_ip(self.vm.mask) |
1419 | + nummask = dotted_to_numeric_ip(mask) |
1420 | |
1421 | numnet = calculate_net_address_from_ip_and_netmask(numip, nummask) |
1422 | |
1423 | - if not self.vm.net: |
1424 | - self.vm.net = numeric_to_dotted_ip(numnet) |
1425 | + net = self.context.get_setting('net') |
1426 | + if not net: |
1427 | + self.context.set_setting('net', numeric_to_dotted_ip(numnet)) |
1428 | |
1429 | - if not self.vm.bcast: |
1430 | + bcast = self.context.get_setting('bcast') |
1431 | + if not bcast: |
1432 | numbcast = calculate_broadcast_address_from_ip_and_netmask(numnet, nummask) |
1433 | - self.vm.bcast = numeric_to_dotted_ip(numbcast) |
1434 | + self.context.set_setting('bcast', numeric_to_dotted_ip(numbcast)) |
1435 | |
1436 | - if not self.vm.gw: |
1437 | + gw = self.context.get_setting('gw') |
1438 | + if not gw: |
1439 | numgw = guess_gw_from_ip(numip) |
1440 | - self.vm.gw = numeric_to_dotted_ip(numgw) |
1441 | - |
1442 | - if not self.vm.dns: |
1443 | - self.vm.dns = self.vm.gw |
1444 | - |
1445 | - self.vm.mask = numeric_to_dotted_ip(nummask) |
1446 | - |
1447 | - logging.debug("net: %s" % self.vm.net) |
1448 | - logging.debug("netmask: %s" % self.vm.mask) |
1449 | - logging.debug("broadcast: %s" % self.vm.bcast) |
1450 | - logging.debug("gateway: %s" % self.vm.gw) |
1451 | - logging.debug("dns: %s" % self.vm.dns) |
1452 | - |
1453 | -register_plugin(NetworkPlugin) |
1454 | + self.context.set_setting('gw', numeric_to_dotted_ip(numgw)) |
1455 | + |
1456 | + dns = self.context.get_setting('dns') |
1457 | + if not dns: |
1458 | + self.context.dns = self.context.gw |
1459 | + self.context.set_setting('dns', self.context.get_setting('gw')) |
1460 | + |
1461 | + self.context.set_setting('mask', numeric_to_dotted_ip(nummask)) |
1462 | + |
1463 | + logging.debug("net: %s" % self.context.get_setting('net')) |
1464 | + logging.debug("netmask: %s" % self.context.get_setting('mask')) |
1465 | + logging.debug("broadcast: %s" % self.context.get_setting('bcast')) |
1466 | + logging.debug("gateway: %s" % self.context.get_setting('gw')) |
1467 | + logging.debug("dns: %s" % self.context.get_setting('dns')) |
1468 | + |
1469 | +register_distro_plugin(NetworkDistroPlugin) |
1470 | +register_hypervisor_plugin(NetworkHypervisorPlugin) |
1471 | |
1472 | === modified file 'VMBuilder/plugins/postinst/__init__.py' |
1473 | --- VMBuilder/plugins/postinst/__init__.py 2009-08-12 22:45:45 +0000 |
1474 | +++ VMBuilder/plugins/postinst/__init__.py 2010-02-18 16:03:14 +0000 |
1475 | @@ -16,7 +16,7 @@ |
1476 | # You should have received a copy of the GNU General Public License |
1477 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
1478 | # |
1479 | -from VMBuilder import register_plugin, Plugin, VMBuilderUserError |
1480 | +from VMBuilder import register_distro_plugin, Plugin, VMBuilderUserError |
1481 | from VMBuilder.util import run_cmd |
1482 | |
1483 | import logging |
1484 | @@ -32,43 +32,43 @@ |
1485 | name ='Post install plugin' |
1486 | |
1487 | def register_options(self): |
1488 | - group = self.vm.setting_group('Post install actions') |
1489 | + group = self.context.setting_group('Post install actions') |
1490 | group.add_option('--copy', metavar='FILE', help="Read 'source dest' lines from FILE, copying source files from host to dest in the guest's file system.") |
1491 | group.add_option('--execscript', '--exec', metavar='SCRIPT', help="Run SCRIPT after distro installation finishes. Script will be called with the guest's chroot as first argument, so you can use 'chroot $1 <cmd>' to run code in the virtual machine.") |
1492 | - self.vm.register_setting_group(group) |
1493 | + self.context.register_setting_group(group) |
1494 | |
1495 | def preflight_check(self): |
1496 | - if self.vm.copy: |
1497 | - logging.debug("Checking if --copy PATH exists: %s" % self.vm.copy) |
1498 | - if not(os.path.isfile(self.vm.copy)): |
1499 | - raise VMBuilderUserError('The path to the --copy directives is invalid: %s. Make sure you are providing a full path.' % self.vm.copy) |
1500 | + if self.context.copy: |
1501 | + logging.debug("Checking if --copy PATH exists: %s" % self.context.copy) |
1502 | + if not(os.path.isfile(self.context.copy)): |
1503 | + raise VMBuilderUserError('The path to the --copy directives is invalid: %s. Make sure you are providing a full path.' % self.context.copy) |
1504 | |
1505 | - if self.vm.execscript: |
1506 | - logging.debug("Checking if --exec PATH exists: %s" % self.vm.execscript) |
1507 | - if not(os.path.isfile(self.vm.execscript)): |
1508 | - raise VMBuilderUserError('The path to the --execscript file is invalid: %s. Make sure you are providing a full path.' % self.vm.execscript) |
1509 | + if self.context.execscript: |
1510 | + logging.debug("Checking if --exec PATH exists: %s" % self.context.execscript) |
1511 | + if not(os.path.isfile(self.context.execscript)): |
1512 | + raise VMBuilderUserError('The path to the --execscript file is invalid: %s. Make sure you are providing a full path.' % self.context.execscript) |
1513 | |
1514 | - logging.debug("Checking permissions of --exec PATH: %s" % self.vm.execscript) |
1515 | - if not os.access(self.vm.execscript, os.X_OK|os.R_OK): |
1516 | - raise VMBuilderUserError('The path to the --execscript file has invalid permissions: %s. Make sure the path is readable and executable.' % self.vm.execscript) |
1517 | + logging.debug("Checking permissions of --exec PATH: %s" % self.context.execscript) |
1518 | + if not os.access(self.context.execscript, os.X_OK|os.R_OK): |
1519 | + raise VMBuilderUserError('The path to the --execscript file has invalid permissions: %s. Make sure the path is readable and executable.' % self.context.execscript) |
1520 | |
1521 | def post_install(self): |
1522 | - if self.vm.copy: |
1523 | - logging.info("Copying files specified by --copy in: %s" % self.vm.copy) |
1524 | + if self.context.copy: |
1525 | + logging.info("Copying files specified by --copy in: %s" % self.context.copy) |
1526 | try: |
1527 | - for line in file(self.vm.copy): |
1528 | + for line in file(self.context.copy): |
1529 | pair = line.strip().split(' ') |
1530 | if len(pair) < 2: # skip blank and incomplete lines |
1531 | continue |
1532 | - util.run_cmd('cp', '-LpR', pair[0], '%s%s' % (self.vm.installdir, pair[1])) |
1533 | + util.run_cmd('cp', '-LpR', pair[0], '%s%s' % (self.context.installdir, pair[1])) |
1534 | |
1535 | except IOError, (errno, strerror): |
1536 | raise VMBuilderUserError("%s executing --copy directives: %s" % (errno, strerror)) |
1537 | |
1538 | - if self.vm.execscript: |
1539 | - logging.info("Executing script: %s" % self.vm.execscript) |
1540 | - util.run_cmd(self.vm.execscript, self.vm.installdir) |
1541 | + if self.context.execscript: |
1542 | + logging.info("Executing script: %s" % self.context.execscript) |
1543 | + util.run_cmd(self.context.execscript, self.vm.installdir) |
1544 | |
1545 | return True |
1546 | |
1547 | -register_plugin(postinst) |
1548 | +#register_plugin(postinst) |
1549 | |
1550 | === modified file 'VMBuilder/plugins/ubuntu/dapper.py' |
1551 | --- VMBuilder/plugins/ubuntu/dapper.py 2009-12-12 04:12:30 +0000 |
1552 | +++ VMBuilder/plugins/ubuntu/dapper.py 2010-02-18 16:03:14 +0000 |
1553 | @@ -25,7 +25,7 @@ |
1554 | import tempfile |
1555 | import VMBuilder |
1556 | import VMBuilder.disk as disk |
1557 | -from VMBuilder.util import run_cmd, give_to_caller |
1558 | +from VMBuilder.util import run_cmd #, give_to_caller |
1559 | |
1560 | class Dapper(suite.Suite): |
1561 | updategrub = "/sbin/update-grub" |
1562 | @@ -48,6 +48,7 @@ |
1563 | return arch in self.valid_flavours.keys() |
1564 | |
1565 | def install(self, destdir): |
1566 | + raise VMBuilderException('Do not call this method!') |
1567 | self.destdir = destdir |
1568 | |
1569 | logging.debug("debootstrapping") |
1570 | @@ -67,7 +68,7 @@ |
1571 | logging.debug("Creating devices") |
1572 | self.create_devices() |
1573 | |
1574 | - if self.vm.hypervisor.needs_bootloader: |
1575 | + if self.distro.hypervisor.needs_bootloader: |
1576 | logging.debug("Installing grub") |
1577 | self.install_grub() |
1578 | |
1579 | @@ -80,7 +81,7 @@ |
1580 | logging.debug('Binding /dev and /proc filesystems') |
1581 | self.mount_dev_proc() |
1582 | |
1583 | - if self.vm.hypervisor.needs_bootloader: |
1584 | + if self.context.hypervisor.needs_bootloader: |
1585 | logging.debug("Installing menu.list") |
1586 | self.install_menu_lst() |
1587 | |
1588 | @@ -120,130 +121,166 @@ |
1589 | logging.debug('Unbinding /dev and /proc filesystems') |
1590 | self.unmount_dev_proc() |
1591 | |
1592 | - if hasattr(self.vm, 'ec2') and self.vm.ec2: |
1593 | + if hasattr(self.context, 'ec2') and self.context.ec2: |
1594 | logging.debug("Configuring for ec2") |
1595 | self.install_ec2() |
1596 | |
1597 | logging.debug("Unpreventing daemons from starting") |
1598 | self.unprevent_daemons_starting() |
1599 | |
1600 | - if self.vm.manifest: |
1601 | + if self.context.manifest: |
1602 | logging.debug("Creating manifest") |
1603 | manifest_contents = self.run_in_target('dpkg-query', '-W', '--showformat=${Package} ${Version}\n') |
1604 | - fp = open(self.vm.manifest, 'w') |
1605 | + fp = open(self.context.manifest, 'w') |
1606 | fp.write(manifest_contents) |
1607 | fp.close |
1608 | - give_to_caller(self.vm.manifest) |
1609 | + give_to_caller(self.context.manifest) |
1610 | |
1611 | def update(self): |
1612 | self.run_in_target('apt-get', '-y', '--force-yes', 'dist-upgrade', |
1613 | env={ 'DEBIAN_FRONTEND' : 'noninteractive' }) |
1614 | |
1615 | def install_authorized_keys(self): |
1616 | - if self.vm.ssh_key: |
1617 | - os.mkdir('%s/root/.ssh' % self.destdir, 0700) |
1618 | - shutil.copy(self.vm.ssh_key, '%s/root/.ssh/authorized_keys' % self.destdir) |
1619 | - os.chmod('%s/root/.ssh/authorized_keys' % self.destdir, 0644) |
1620 | - if self.vm.ssh_user_key: |
1621 | - os.mkdir('%s/home/%s/.ssh' % (self.destdir, self.vm.user), 0700) |
1622 | - shutil.copy(self.vm.ssh_user_key, '%s/home/%s/.ssh/authorized_keys' % (self.destdir, self.vm.user)) |
1623 | - os.chmod('%s/home/%s/.ssh/authorized_keys' % (self.destdir, self.vm.user), 0644) |
1624 | - self.run_in_target('chown', '-R', '%s:%s' % (self.vm.user,)*2, '/home/%s/.ssh/' % (self.vm.user)) |
1625 | - |
1626 | - if self.vm.ssh_user_key or self.vm.ssh_key: |
1627 | - if not self.vm.addpkg: |
1628 | - self.vm.addpkg = [] |
1629 | - self.vm.addpkg += ['openssh-server'] |
1630 | + ssh_key = self.context.get_setting('ssh-key') |
1631 | + if ssh_key: |
1632 | + os.mkdir('%s/root/.ssh' % self.context.chroot_dir, 0700) |
1633 | + shutil.copy(ssh_key, '%s/root/.ssh/authorized_keys' % self.context.chroot_dir) |
1634 | + os.chmod('%s/root/.ssh/authorized_keys' % self.context.chroot_dir, 0644) |
1635 | + |
1636 | + user = self.context.get_setting('user') |
1637 | + ssh_user_key = self.context.get_setting('ssh-user-key') |
1638 | + if ssh_user_key: |
1639 | + os.mkdir('%s/home/%s/.ssh' % (self.context.chroot_dir, user), 0700) |
1640 | + shutil.copy(ssh_user_key, '%s/home/%s/.ssh/authorized_keys' % (self.context.chroot_dir, user)) |
1641 | + os.chmod('%s/home/%s/.ssh/authorized_keys' % (self.context.chroot_dir, user), 0644) |
1642 | + self.run_in_target('chown', '-R', '%s:%s' % (user,)*2, '/home/%s/.ssh/' % (user)) |
1643 | + |
1644 | + if ssh_user_key or ssh_key: |
1645 | + addpkg = self.context.get_setting('addpkg') |
1646 | + addpkg += ['openssh-server'] |
1647 | + self.context.set_setting('addpkg', addpkg) |
1648 | |
1649 | def mount_dev_proc(self): |
1650 | - run_cmd('mount', '--bind', '/dev', '%s/dev' % self.destdir) |
1651 | - self.vm.add_clean_cmd('umount', '%s/dev' % self.destdir, ignore_fail=True) |
1652 | + run_cmd('mount', '--bind', '/dev', '%s/dev' % self.context.chroot_dir) |
1653 | + self.context.add_clean_cb(self.unmount_dev) |
1654 | |
1655 | - run_cmd('mount', '--bind', '/dev/pts', '%s/dev/pts' % self.destdir) |
1656 | - self.vm.add_clean_cmd('umount', '%s/dev/pts' % self.destdir, ignore_fail=True) |
1657 | + run_cmd('mount', '--bind', '/dev/pts', '%s/dev/pts' % self.context.chroot_dir) |
1658 | + self.context.add_clean_cb(self.unmount_dev_pts) |
1659 | |
1660 | self.run_in_target('mount', '-t', 'proc', 'proc', '/proc') |
1661 | - self.vm.add_clean_cmd('umount', '%s/proc' % self.destdir, ignore_fail=True) |
1662 | - |
1663 | - def unmount_dev_proc(self): |
1664 | - run_cmd('umount', '%s/dev/pts' % self.destdir) |
1665 | - run_cmd('umount', '%s/dev' % self.destdir) |
1666 | - run_cmd('umount', '%s/proc' % self.destdir) |
1667 | + self.context.add_clean_cb(self.unmount_proc) |
1668 | + |
1669 | + def unmount_proc(self): |
1670 | + self.context.cancel_cleanup(self.unmount_proc) |
1671 | + run_cmd('umount', '%s/proc' % self.context.chroot_dir) |
1672 | + |
1673 | + def unmount_dev_pts(self): |
1674 | + self.context.cancel_cleanup(self.unmount_dev_pts) |
1675 | + run_cmd('umount', '%s/dev/pts' % self.context.chroot_dir) |
1676 | + |
1677 | + def unmount_dev(self): |
1678 | + self.context.cancel_cleanup(self.unmount_dev) |
1679 | + run_cmd('umount', '%s/dev' % self.context.chroot_dir) |
1680 | |
1681 | def update_passwords(self): |
1682 | # Set the user password, using md5 |
1683 | - self.run_in_target(stdin=('%s:%s\n' % (self.vm.user, getattr(self.vm, 'pass'))), *self.chpasswd_cmd) |
1684 | + user = self.context.get_setting('user') |
1685 | + passwd = self.context.get_setting('pass') |
1686 | + self.run_in_target(stdin=('%s:%s\n' % (user, passwd)), *self.chpasswd_cmd) |
1687 | |
1688 | # Lock root account only if we didn't set the root password |
1689 | - if self.vm.rootpass: |
1690 | - self.run_in_target(stdin=('%s:%s\n' % ('root', self.vm.rootpass)), *self.chpasswd_cmd) |
1691 | + rootpass = self.context.get_setting('rootpass') |
1692 | + if rootpass: |
1693 | + self.run_in_target(stdin=('%s:%s\n' % ('root', rootpass)), *self.chpasswd_cmd) |
1694 | else: |
1695 | self.run_in_target('usermod', '-L', 'root') |
1696 | |
1697 | - if self.vm.lock_user: |
1698 | - logging.info('Locking %s' %(self.vm.user)) |
1699 | - self.run_in_target('usermod', '-L', self.vm.user) |
1700 | + lock_user = self.context.get_setting('lock-user') |
1701 | + if lock_user: |
1702 | + logging.info('Locking %s' % (user, )) |
1703 | + self.run_in_target('usermod', '-L', user) |
1704 | |
1705 | def create_initial_user(self): |
1706 | - if self.vm.uid: |
1707 | - self.run_in_target('adduser', '--disabled-password', '--uid', self.vm.uid, '--gecos', self.vm.name, self.vm.user) |
1708 | + uid = self.context.get_setting('uid') |
1709 | + name = self.context.get_setting('name') |
1710 | + user = self.context.get_setting('user') |
1711 | + if uid: |
1712 | + self.run_in_target('adduser', '--disabled-password', '--uid', uid, '--gecos', name, user) |
1713 | else: |
1714 | - self.run_in_target('adduser', '--disabled-password', '--gecos', self.vm.name, self.vm.user) |
1715 | + self.run_in_target('adduser', '--disabled-password', '--gecos', name, user) |
1716 | + |
1717 | self.run_in_target('addgroup', '--system', 'admin') |
1718 | - self.run_in_target('adduser', self.vm.user, 'admin') |
1719 | + self.run_in_target('adduser', user, 'admin') |
1720 | |
1721 | self.install_from_template('/etc/sudoers', 'sudoers') |
1722 | for group in ['adm', 'audio', 'cdrom', 'dialout', 'floppy', 'video', 'plugdev', 'dip', 'netdev', 'powerdev', 'lpadmin', 'scanner']: |
1723 | - self.run_in_target('adduser', self.vm.user, group, ignore_fail=True) |
1724 | + self.run_in_target('adduser', user, group, ignore_fail=True) |
1725 | |
1726 | self.update_passwords() |
1727 | |
1728 | def kernel_name(self): |
1729 | - return 'linux-image-%s' % (self.vm.flavour or self.default_flavour[self.vm.arch],) |
1730 | - |
1731 | - def config_network(self): |
1732 | - self.vm.install_file('/etc/hostname', self.vm.hostname) |
1733 | - self.install_from_template('/etc/hosts', 'etc_hosts', { 'hostname' : self.vm.hostname, 'domain' : self.vm.domain }) |
1734 | - self.install_from_template('/etc/network/interfaces', 'interfaces') |
1735 | + flavour = self.context.get_setting('flavour') |
1736 | + arch = self.context.get_setting('arch') |
1737 | + return 'linux-image-%s' % (flavour or self.default_flavour[arch],) |
1738 | + |
1739 | + def config_host_and_domainname(self): |
1740 | + hostname = self.context.get_setting('hostname') |
1741 | + domain = self.context.get_setting('domain') |
1742 | + self.context.install_file('/etc/hostname', hostname) |
1743 | + self.install_from_template('/etc/hosts', 'etc_hosts', { 'hostname' : hostname, 'domain' : domain }) |
1744 | + |
1745 | + def config_interfaces(self, nics): |
1746 | + self.install_from_template('/etc/network/interfaces', 'interfaces', { 'ip' : nics[0].type == 'dhcp' and 'dhcp' or nics[0].ip }) |
1747 | |
1748 | def unprevent_daemons_starting(self): |
1749 | - os.unlink('%s/usr/sbin/policy-rc.d' % self.destdir) |
1750 | + os.unlink('%s/usr/sbin/policy-rc.d' % self.context.chroot_dir) |
1751 | |
1752 | def prevent_daemons_starting(self): |
1753 | os.chmod(self.install_from_template('/usr/sbin/policy-rc.d', 'nostart-policy-rc.d'), 0755) |
1754 | |
1755 | def install_extras(self): |
1756 | - if not self.vm.addpkg and not self.vm.removepkg: |
1757 | + addpkg = self.context.get_setting('addpkg') |
1758 | + removepkg = self.context.get_setting('removepkg') |
1759 | + if not addpkg and not removepkg: |
1760 | return |
1761 | cmd = ['apt-get', 'install', '-y', '--force-yes'] |
1762 | - cmd += self.vm.addpkg or [] |
1763 | - cmd += ['%s-' % pkg for pkg in self.vm.removepkg or []] |
1764 | + cmd += addpkg or [] |
1765 | + cmd += ['%s-' % pkg for pkg in removepkg or []] |
1766 | self.run_in_target(env={ 'DEBIAN_FRONTEND' : 'noninteractive' }, *cmd) |
1767 | |
1768 | def unmount_volatile(self): |
1769 | - for mntpnt in glob.glob('%s/lib/modules/*/volatile' % self.destdir): |
1770 | + for mntpnt in glob.glob('%s/lib/modules/*/volatile' % self.context.chroot_dir): |
1771 | logging.debug("Unmounting %s" % mntpnt) |
1772 | run_cmd('umount', mntpnt) |
1773 | |
1774 | - def install_menu_lst(self): |
1775 | + def install_menu_lst(self, disks): |
1776 | self.run_in_target(self.updategrub, '-y') |
1777 | - self.mangle_grub_menu_lst() |
1778 | + self.mangle_grub_menu_lst(disks) |
1779 | self.run_in_target(self.updategrub) |
1780 | self.run_in_target('grub-set-default', '0') |
1781 | |
1782 | - def mangle_grub_menu_lst(self): |
1783 | - bootdev = disk.bootpart(self.vm.disks) |
1784 | - run_cmd('sed', '-ie', 's/^# kopt=root=\([^ ]*\)\(.*\)/# kopt=root=\/dev\/hd%s%d\\2/g' % (bootdev.disk.devletters(), bootdev.get_index()+1), '%s/boot/grub/menu.lst' % self.destdir) |
1785 | - run_cmd('sed', '-ie', 's/^# groot.*/# groot %s/g' % bootdev.get_grub_id(), '%s/boot/grub/menu.lst' % self.destdir) |
1786 | - run_cmd('sed', '-ie', '/^# kopt_2_6/ d', '%s/boot/grub/menu.lst' % self.destdir) |
1787 | + def mangle_grub_menu_lst(self, disks): |
1788 | + bootdev = disk.bootpart(disks) |
1789 | + run_cmd('sed', '-ie', 's/^# kopt=root=\([^ ]*\)\(.*\)/# kopt=root=\/dev\/hd%s%d\\2/g' % (bootdev.disk.devletters(), bootdev.get_index()+1), '%s/boot/grub/menu.lst' % self.context.chroot_dir) |
1790 | + run_cmd('sed', '-ie', 's/^# groot.*/# groot %s/g' % bootdev.get_grub_id(), '%s/boot/grub/menu.lst' % self.context.chroot_dir) |
1791 | + run_cmd('sed', '-ie', '/^# kopt_2_6/ d', '%s/boot/grub/menu.lst' % self.context.chroot_dir) |
1792 | |
1793 | def install_sources_list(self, final=False): |
1794 | if final: |
1795 | - mirror, updates_mirror, security_mirror = self.vm.mirror, self.vm.mirror, self.vm.security_mirror |
1796 | + mirror = updates_mirror = self.context.get_setting('mirror') |
1797 | + security_mirror = self.context.get_setting('security-mirror') |
1798 | else: |
1799 | mirror, updates_mirror, security_mirror = self.install_mirrors() |
1800 | |
1801 | - self.install_from_template('/etc/apt/sources.list', 'sources.list', { 'mirror' : mirror, 'security_mirror' : security_mirror, 'updates_mirror' : updates_mirror }) |
1802 | + components = self.context.get_setting('components') |
1803 | + ppa = self.context.get_setting('ppa') |
1804 | + suite = self.context.get_setting('suite') |
1805 | + self.install_from_template('/etc/apt/sources.list', 'sources.list', { 'mirror' : mirror, |
1806 | + 'security_mirror' : security_mirror, |
1807 | + 'updates_mirror' : updates_mirror, |
1808 | + 'components' : components, |
1809 | + 'ppa' : ppa, |
1810 | + 'suite' : suite }) |
1811 | |
1812 | # If setting up the final mirror, allow apt-get update to fail |
1813 | # (since we might be on a complete different network than the |
1814 | @@ -251,34 +288,40 @@ |
1815 | self.run_in_target('apt-get', 'update', ignore_fail=final) |
1816 | |
1817 | def install_apt_proxy(self): |
1818 | - if self.vm.proxy is not None: |
1819 | - self.vm.install_file('/etc/apt/apt.conf', '// Proxy added by vmbuilder\nAcquire::http { Proxy "%s"; };' % self.vm.proxy) |
1820 | + proxy = self.context.get_setting('proxy') |
1821 | + if proxy is not None: |
1822 | + self.context.install_file('/etc/apt/apt.conf', '// Proxy added by vmbuilder\nAcquire::http { Proxy "%s"; };' % proxy) |
1823 | |
1824 | - def install_fstab(self): |
1825 | - if self.vm.hypervisor.preferred_storage == VMBuilder.hypervisor.STORAGE_FS_IMAGE: |
1826 | - self.install_from_template('/etc/fstab', 'dapper_fstab_fsimage', { 'fss' : disk.get_ordered_filesystems(self.vm), 'prefix' : self.disk_prefix }) |
1827 | - else: |
1828 | - self.install_from_template('/etc/fstab', 'dapper_fstab', { 'parts' : disk.get_ordered_partitions(self.vm.disks), 'prefix' : self.disk_prefix }) |
1829 | + def install_fstab(self, disks, filesystems): |
1830 | + self.install_from_template('/etc/fstab', 'dapper_fstab', { 'parts' : disk.get_ordered_partitions(disks), 'prefix' : self.disk_prefix }) |
1831 | |
1832 | def install_device_map(self): |
1833 | self.install_from_template('/boot/grub/device.map', 'devicemap', { 'prefix' : self.disk_prefix }) |
1834 | |
1835 | def debootstrap(self): |
1836 | - cmd = ['/usr/sbin/debootstrap', '--arch=%s' % self.vm.arch] |
1837 | - if self.vm.variant: |
1838 | - cmd += ['--variant=%s' % self.vm.variant] |
1839 | - cmd += [self.vm.suite, self.destdir, self.debootstrap_mirror()] |
1840 | + arch = self.context.get_setting('arch') |
1841 | + cmd = ['/usr/sbin/debootstrap', '--arch=%s' % arch] |
1842 | + |
1843 | + variant = self.context.get_setting('variant') |
1844 | + if variant: |
1845 | + cmd += ['--variant=%s' % variant] |
1846 | + |
1847 | + suite = self.context.get_setting('suite') |
1848 | + cmd += [suite, self.context.chroot_dir, self.debootstrap_mirror()] |
1849 | kwargs = { 'env' : { 'DEBIAN_FRONTEND' : 'noninteractive' } } |
1850 | - if self.vm.proxy: |
1851 | - kwargs['env']['http_proxy'] = self.vm.proxy |
1852 | + |
1853 | + proxy = self.context.get_setting('proxy') |
1854 | + if proxy: |
1855 | + kwargs['env']['http_proxy'] = proxy |
1856 | run_cmd(*cmd, **kwargs) |
1857 | |
1858 | def debootstrap_mirror(self): |
1859 | - if self.vm.iso: |
1860 | + iso = self.context.get_setting('iso') |
1861 | + if iso: |
1862 | isodir = tempfile.mkdtemp() |
1863 | - self.vm.add_clean_cb(lambda:os.rmdir(isodir)) |
1864 | - run_cmd('mount', '-o', 'loop', '-t', 'iso9660', self.vm.iso, isodir) |
1865 | - self.vm.add_clean_cmd('umount', isodir) |
1866 | + self.context.add_clean_cb(lambda:os.rmdir(isodir)) |
1867 | + run_cmd('mount', '-o', 'loop', '-t', 'iso9660', iso, isodir) |
1868 | + self.context.add_clean_cmd('umount', isodir) |
1869 | self.iso_mounted = True |
1870 | |
1871 | return 'file://%s' % isodir |
1872 | @@ -287,46 +330,48 @@ |
1873 | |
1874 | |
1875 | def install_mirrors(self): |
1876 | - if self.vm.install_mirror: |
1877 | - mirror = self.vm.install_mirror |
1878 | - else: |
1879 | - mirror = self.vm.mirror |
1880 | - |
1881 | - if self.vm.install_mirror: |
1882 | - updates_mirror = self.vm.install_mirror |
1883 | - else: |
1884 | - updates_mirror = self.vm.mirror |
1885 | - |
1886 | - if self.vm.install_security_mirror: |
1887 | - security_mirror = self.vm.install_security_mirror |
1888 | - else: |
1889 | - security_mirror = self.vm.security_mirror |
1890 | + install_mirror = self.context.get_setting('install-mirror') |
1891 | + if install_mirror: |
1892 | + mirror = install_mirror |
1893 | + else: |
1894 | + mirror = self.context.get_setting('mirror') |
1895 | + |
1896 | + updates_mirror = mirror |
1897 | + |
1898 | + install_security_mirror = self.context.get_setting('install-security-mirror') |
1899 | + if install_security_mirror: |
1900 | + security_mirror = install_security_mirror |
1901 | + else: |
1902 | + security_mirror = self.context.get_setting('security-mirror') |
1903 | |
1904 | return (mirror, updates_mirror, security_mirror) |
1905 | |
1906 | - def install_kernel(self): |
1907 | + def install_kernel(self, destdir): |
1908 | self.install_from_template('/etc/kernel-img.conf', 'kernelimg', { 'updategrub' : self.updategrub }) |
1909 | - run_cmd('chroot', self.destdir, 'apt-get', '--force-yes', '-y', 'install', self.kernel_name(), 'grub') |
1910 | + run_cmd('chroot', destdir, 'apt-get', '--force-yes', '-y', 'install', self.kernel_name(), 'grub') |
1911 | |
1912 | - def install_grub(self): |
1913 | + def install_grub(self, chroot_dir): |
1914 | + arch = self.context.get_setting('arch') |
1915 | self.run_in_target('apt-get', '--force-yes', '-y', 'install', 'grub') |
1916 | - run_cmd('rsync', '-a', '%s%s/%s/' % (self.destdir, self.grubroot, self.vm.arch == 'amd64' and 'x86_64-pc' or 'i386-pc'), '%s/boot/grub/' % self.destdir) |
1917 | + run_cmd('rsync', '-a', '%s%s/%s/' % (chroot_dir, self.grubroot, arch == 'amd64' and 'x86_64-pc' or 'i386-pc'), '%s/boot/grub/' % chroot_dir) |
1918 | |
1919 | def create_devices(self): |
1920 | - import VMBuilder.plugins.xen |
1921 | + pass |
1922 | +# FIXME |
1923 | +# import VMBuilder.plugins.xen |
1924 | |
1925 | - if isinstance(self.vm.hypervisor, VMBuilder.plugins.xen.Xen): |
1926 | - self.run_in_target('mknod', '/dev/xvda', 'b', '202', '0') |
1927 | - self.run_in_target('mknod', '/dev/xvda1', 'b', '202', '1') |
1928 | - self.run_in_target('mknod', '/dev/xvda2', 'b', '202', '2') |
1929 | - self.run_in_target('mknod', '/dev/xvda3', 'b', '202', '3') |
1930 | - self.run_in_target('mknod', '/dev/xvc0', 'c', '204', '191') |
1931 | +# if isinstance(self.context.hypervisor, VMBuilder.plugins.xen.Xen): |
1932 | +# self.run_in_target('mknod', '/dev/xvda', 'b', '202', '0') |
1933 | +# self.run_in_target('mknod', '/dev/xvda1', 'b', '202', '1') |
1934 | +# self.run_in_target('mknod', '/dev/xvda2', 'b', '202', '2') |
1935 | +# self.run_in_target('mknod', '/dev/xvda3', 'b', '202', '3') |
1936 | +# self.run_in_target('mknod', '/dev/xvc0', 'c', '204', '191') |
1937 | |
1938 | def install_from_template(self, *args, **kwargs): |
1939 | - return self.vm.distro.install_from_template(*args, **kwargs) |
1940 | + return self.context.install_from_template(*args, **kwargs) |
1941 | |
1942 | def run_in_target(self, *args, **kwargs): |
1943 | - return self.vm.distro.run_in_target(*args, **kwargs) |
1944 | + return self.context.run_in_target(*args, **kwargs) |
1945 | |
1946 | def copy_to_target(self, infile, destpath): |
1947 | logging.debug("Copying %s on host to %s in guest" % (infile, destpath)) |
1948 | @@ -350,9 +395,9 @@ |
1949 | self.copy_to_target('/etc/default/locale', '/etc/default/locale') |
1950 | self.run_in_target('dpkg-reconfigure', '-fnoninteractive', '-pcritical', 'libc6') |
1951 | self.run_in_target('locale-gen', 'en_US') |
1952 | - if self.vm.lang: |
1953 | - self.run_in_target('locale-gen', self.vm.lang) |
1954 | - self.install_from_template('/etc/default/locale', 'locale', { 'lang' : self.vm.lang }) |
1955 | + if self.context.lang: |
1956 | + self.run_in_target('locale-gen', self.context.lang) |
1957 | + self.install_from_template('/etc/default/locale', 'locale', { 'lang' : self.context.lang }) |
1958 | self.run_in_target('dpkg-reconfigure', '-fnoninteractive', '-pcritical', 'locales') |
1959 | self.run_in_target('dpkg-reconfigure', '-pcritical', 'locales') |
1960 | |
1961 | @@ -360,12 +405,13 @@ |
1962 | shutil.copy(logfile, '%s/var/log/vmbuilder-install.log' % (rootdir,)) |
1963 | |
1964 | def set_timezone(self): |
1965 | - if self.vm.timezone: |
1966 | - os.unlink('%s/etc/localtime' % self.destdir) |
1967 | - shutil.copy('%s/usr/share/zoneinfo/%s' % (self.destdir, self.vm.timezone), '%s/etc/localtime' % (self.destdir,)) |
1968 | + timezone = self.context.get_setting('timezone') |
1969 | + if timezone: |
1970 | + os.unlink('%s/etc/localtime' % self.context.chroot_dir) |
1971 | + shutil.copy('%s/usr/share/zoneinfo/%s' % (self.context.chroot_dir, timezone), '%s/etc/localtime' % (self.context.chroot_dir,)) |
1972 | |
1973 | def install_ec2(self): |
1974 | - if self.vm.ec2: |
1975 | + if self.context.ec2: |
1976 | logging.debug('This suite does not support ec2') |
1977 | |
1978 | def disable_hwclock_access(self): |
1979 | @@ -373,3 +419,6 @@ |
1980 | fp.write('HWCLOCKACCESS=no') |
1981 | fp.close() |
1982 | |
1983 | + def has_256_bit_inode_ext3_support(self): |
1984 | + return False |
1985 | + |
1986 | |
1987 | === modified file 'VMBuilder/plugins/ubuntu/distro.py' |
1988 | --- VMBuilder/plugins/ubuntu/distro.py 2010-01-19 17:43:04 +0000 |
1989 | +++ VMBuilder/plugins/ubuntu/distro.py 2010-02-18 16:03:14 +0000 |
1990 | @@ -39,66 +39,66 @@ |
1991 | xen_kernel = '' |
1992 | |
1993 | def register_options(self): |
1994 | - group = self.vm.setting_group('Package options') |
1995 | - group.add_option('--addpkg', action='append', metavar='PKG', help='Install PKG into the guest (can be specfied multiple times).') |
1996 | - group.add_option('--removepkg', action='append', metavar='PKG', help='Remove PKG from the guest (can be specfied multiple times)') |
1997 | - self.vm.register_setting_group(group) |
1998 | + group = self.setting_group('Package options') |
1999 | + group.add_setting('addpkg', type='list', metavar='PKG', help='Install PKG into the guest (can be specfied multiple times).') |
2000 | + group.add_setting('removepkg', type='list', metavar='PKG', help='Remove PKG from the guest (can be specfied multiple times)') |
2001 | |
2002 | - group = self.vm.setting_group('General OS options') |
2003 | + group = self.setting_group('General OS options') |
2004 | self.host_arch = run_cmd('dpkg', '--print-architecture').rstrip() |
2005 | - group.add_option('-a', '--arch', default=self.host_arch, help='Specify the target architecture. Valid options: amd64 i386 lpia (defaults to host arch)') |
2006 | - group.add_option('--hostname', default='ubuntu', help='Set NAME as the hostname of the guest. Default: ubuntu. Also uses this name as the VM name.') |
2007 | - self.vm.register_setting_group(group) |
2008 | - |
2009 | - group = self.vm.setting_group('Installation options') |
2010 | - group.add_option('--suite', default='jaunty', help='Suite to install. Valid options: %s [default: %%default]' % ' '.join(self.suites)) |
2011 | - group.add_option('--flavour', '--kernel-flavour', help='Kernel flavour to use. Default and valid options depend on architecture and suite') |
2012 | - group.add_option('--variant', metavar='VARIANT', help='Passed to debootstrap --variant flag; use minbase, buildd, or fakechroot.') |
2013 | - group.add_option('--iso', metavar='PATH', help='Use an iso image as the source for installation of file. Full path to the iso must be provided. If --mirror is also provided, it will be used in the final sources.list of the vm. This requires suite and kernel parameter to match what is available on the iso, obviously.') |
2014 | - group.add_option('--mirror', metavar='URL', help='Use Ubuntu mirror at URL instead of the default, which is http://archive.ubuntu.com/ubuntu for official arches and http://ports.ubuntu.com/ubuntu-ports otherwise') |
2015 | - group.add_option('--proxy', metavar='URL', help='Use proxy at URL for cached packages') |
2016 | - group.add_option('--install-mirror', metavar='URL', help='Use Ubuntu mirror at URL for the installation only. Apt\'s sources.list will still use default or URL set by --mirror') |
2017 | - group.add_option('--security-mirror', metavar='URL', help='Use Ubuntu security mirror at URL instead of the default, which is http://security.ubuntu.com/ubuntu for official arches and http://ports.ubuntu.com/ubuntu-ports otherwise.') |
2018 | - group.add_option('--install-security-mirror', metavar='URL', help='Use the security mirror at URL for installation only. Apt\'s sources.list will still use default or URL set by --security-mirror') |
2019 | - group.add_option('--components', metavar='COMPS', help='A comma seperated list of distro components to include (e.g. main,universe).') |
2020 | - group.add_option('--ppa', metavar='PPA', action='append', help='Add ppa belonging to PPA to the vm\'s sources.list.') |
2021 | - group.add_option('--lang', metavar='LANG', default=self.get_locale(), help='Set the locale to LANG [default: %default]') |
2022 | - group.add_option('--timezone', metavar='TZ', default='UTC', help='Set the timezone to TZ in the vm. [default: %default]') |
2023 | - self.vm.register_setting_group(group) |
2024 | - |
2025 | - group = self.vm.setting_group('Settings for the initial user') |
2026 | - group.add_option('--user', default='ubuntu', help='Username of initial user [default: %default]') |
2027 | - group.add_option('--name', default='Ubuntu', help='Full name of initial user [default: %default]') |
2028 | - group.add_option('--pass', default='ubuntu', help='Password of initial user [default: %default]') |
2029 | - group.add_option('--rootpass', help='Initial root password (WARNING: this has strong security implications).') |
2030 | - group.add_option('--uid', help='Initial UID value.') |
2031 | - group.add_option('--gid', help='Initial GID value.') |
2032 | - group.add_option('--lock-user', action='store_true', help='Lock the initial user [default %default]') |
2033 | - self.vm.register_setting_group(group) |
2034 | - |
2035 | - group = self.vm.setting_group('Other options') |
2036 | - group.add_option('--ssh-key', metavar='PATH', help='Add PATH to root\'s ~/.ssh/authorized_keys (WARNING: this has strong security implications).') |
2037 | - group.add_option('--ssh-user-key', help='Add PATH to the user\'s ~/.ssh/authorized_keys.') |
2038 | - group.add_option('--manifest', metavar='PATH', help='If passed, a manifest will be written to PATH') |
2039 | - self.vm.register_setting_group(group) |
2040 | + group.add_setting('arch', extra_args=['-a'], default=self.host_arch, help='Specify the target architecture. Valid options: amd64 i386 lpia (defaults to host arch)') |
2041 | + group.add_setting('hostname', default='ubuntu', help='Set NAME as the hostname of the guest. Default: ubuntu. Also uses this name as the VM name.') |
2042 | + |
2043 | + group = self.setting_group('Installation options') |
2044 | + group.add_setting('suite', default='jaunty', help='Suite to install. Valid options: %s [default: %%default]' % ' '.join(self.suites)) |
2045 | + group.add_setting('flavour', extra_args=['--kernel-flavour'], help='Kernel flavour to use. Default and valid options depend on architecture and suite') |
2046 | + group.add_setting('variant', metavar='VARIANT', help='Passed to debootstrap --variant flag; use minbase, buildd, or fakechroot.') |
2047 | + group.add_setting('iso', metavar='PATH', help='Use an iso image as the source for installation of file. Full path to the iso must be provided. If --mirror is also provided, it will be used in the final sources.list of the vm. This requires suite and kernel parameter to match what is available on the iso, obviously.') |
2048 | + group.add_setting('mirror', metavar='URL', help='Use Ubuntu mirror at URL instead of the default, which is http://archive.ubuntu.com/ubuntu for official arches and http://ports.ubuntu.com/ubuntu-ports otherwise') |
2049 | + group.add_setting('proxy', metavar='URL', help='Use proxy at URL for cached packages') |
2050 | + group.add_setting('install-mirror', metavar='URL', help='Use Ubuntu mirror at URL for the installation only. Apt\'s sources.list will still use default or URL set by --mirror') |
2051 | + group.add_setting('security-mirror', metavar='URL', help='Use Ubuntu security mirror at URL instead of the default, which is http://security.ubuntu.com/ubuntu for official arches and http://ports.ubuntu.com/ubuntu-ports otherwise.') |
2052 | + group.add_setting('install-security-mirror', metavar='URL', help='Use the security mirror at URL for installation only. Apt\'s sources.list will still use default or URL set by --security-mirror') |
2053 | + group.add_setting('components', type='list', metavar='COMPS', help='A comma seperated list of distro components to include (e.g. main,universe).') |
2054 | + group.add_setting('ppa', metavar='PPA', type='list', help='Add ppa belonging to PPA to the vm\'s sources.list.') |
2055 | + group.add_setting('lang', metavar='LANG', default=self.get_locale(), help='Set the locale to LANG [default: %default]') |
2056 | + group.add_setting('timezone', metavar='TZ', default='UTC', help='Set the timezone to TZ in the vm. [default: %default]') |
2057 | + |
2058 | + group = self.setting_group('Settings for the initial user') |
2059 | + group.add_setting('user', default='ubuntu', help='Username of initial user [default: %default]') |
2060 | + group.add_setting('name', default='Ubuntu', help='Full name of initial user [default: %default]') |
2061 | + group.add_setting('pass', default='ubuntu', help='Password of initial user [default: %default]') |
2062 | + group.add_setting('rootpass', help='Initial root password (WARNING: this has strong security implications).') |
2063 | + group.add_setting('uid', type='int', help='Initial UID value.') |
2064 | + group.add_setting('gid', help='Initial GID value.') |
2065 | + group.add_setting('lock-user', type='bool', default=False, help='Lock the initial user [default: %default]') |
2066 | + |
2067 | + group = self.setting_group('Other options') |
2068 | + group.add_setting('ssh-key', metavar='PATH', help='Add PATH to root\'s ~/.ssh/authorized_keys (WARNING: this has strong security implications).') |
2069 | + group.add_setting('ssh-user-key', help='Add PATH to the user\'s ~/.ssh/authorized_keys.') |
2070 | + group.add_setting('manifest', metavar='PATH', help='If passed, a manifest will be written to PATH') |
2071 | |
2072 | def set_defaults(self): |
2073 | - if not self.vm.mirror: |
2074 | - if self.vm.arch == 'lpia': |
2075 | - self.vm.mirror = 'http://ports.ubuntu.com/ubuntu-ports' |
2076 | - else: |
2077 | - self.vm.mirror = 'http://archive.ubuntu.com/ubuntu' |
2078 | - |
2079 | - if not self.vm.security_mirror: |
2080 | - if self.vm.arch == 'lpia': |
2081 | - self.vm.security_mirror = 'http://ports.ubuntu.com/ubuntu-ports' |
2082 | - else: |
2083 | - self.vm.security_mirror = 'http://security.ubuntu.com/ubuntu' |
2084 | - |
2085 | - if not self.vm.components: |
2086 | - self.vm.components = ['main', 'restricted', 'universe'] |
2087 | + mirror = self.get_setting('mirror') |
2088 | + security_mirror = self.get_setting('security-mirror') |
2089 | + arch = self.get_setting('arch') |
2090 | + components = self.get_setting('components') |
2091 | + |
2092 | + if not mirror: |
2093 | + if arch == 'lpia': |
2094 | + self.set_setting_default('mirror', 'http://ports.ubuntu.com/ubuntu-ports') |
2095 | + else: |
2096 | + self.set_setting_default('mirror', 'http://archive.ubuntu.com/ubuntu') |
2097 | + |
2098 | + if not security_mirror: |
2099 | + if arch == 'lpia': |
2100 | + self.set_setting_default('security-mirror', 'http://ports.ubuntu.com/ubuntu-ports') |
2101 | + else: |
2102 | + self.set_setting_default('security-mirror', 'http://security.ubuntu.com/ubuntu') |
2103 | + |
2104 | + if not components: |
2105 | + self.set_setting_default('components', ['main', 'restricted', 'universe']) |
2106 | else: |
2107 | - self.vm.components = self.vm.components.split(',') |
2108 | + self.set_setting_default('components', components.split(',')) |
2109 | |
2110 | def get_locale(self): |
2111 | return os.getenv('LANG') |
2112 | @@ -108,40 +108,70 @@ |
2113 | lead to failure, and since we can check them before we start setting up disk |
2114 | and whatnot, we might as well go ahead an do this now.""" |
2115 | |
2116 | - if not self.vm.suite in self.suites: |
2117 | - raise VMBuilderUserError('Invalid suite. Valid suites are: %s' % ' '.join(self.suites)) |
2118 | + suite = self.get_setting('suite') |
2119 | + if not suite in self.suites: |
2120 | + raise VMBuilderUserError('Invalid suite: "%s". Valid suites are: %s' % (suite, ' '.join(self.suites))) |
2121 | |
2122 | - modname = 'VMBuilder.plugins.ubuntu.%s' % (self.vm.suite, ) |
2123 | - mod = __import__(modname, fromlist=[self.vm.suite]) |
2124 | - self.suite = getattr(mod, self.vm.suite.capitalize())(self.vm) |
2125 | + modname = 'VMBuilder.plugins.ubuntu.%s' % (suite, ) |
2126 | + mod = __import__(modname, fromlist=[suite]) |
2127 | + self.suite = getattr(mod, suite.capitalize())(self) |
2128 | |
2129 | - if self.vm.arch not in self.valid_archs[self.host_arch] or \ |
2130 | - not self.suite.check_arch_validity(self.vm.arch): |
2131 | - raise VMBuilderUserError('%s is not a valid architecture. Valid architectures are: %s' % (self.vm.arch, |
2132 | + arch = self.get_setting('arch') |
2133 | + if arch not in self.valid_archs[self.host_arch] or \ |
2134 | + not self.suite.check_arch_validity(arch): |
2135 | + raise VMBuilderUserError('%s is not a valid architecture. Valid architectures are: %s' % (arch, |
2136 | ' '.join(self.valid_archs[self.host_arch]))) |
2137 | |
2138 | - if not self.vm.components: |
2139 | - self.vm.components = ['main', 'restricted', 'universe'] |
2140 | + components = self.get_setting('components') |
2141 | + if not components: |
2142 | + self.set_config_value_list = ['main', 'restricted', 'universe'] |
2143 | else: |
2144 | - if type(self.vm.components) is str: |
2145 | + if type(components) is str: |
2146 | self.vm.components = self.vm.components.split(',') |
2147 | |
2148 | - if self.vm.hypervisor.name == 'Xen': |
2149 | - logging.info('Xen kernel default: linux-image-%s %s', self.suite.xen_kernel_flavour, self.xen_kernel_version()) |
2150 | - |
2151 | - self.vm.virtio_net = self.use_virtio_net() |
2152 | - |
2153 | - if self.vm.lang: |
2154 | + self.context.virtio_net = self.use_virtio_net() |
2155 | + |
2156 | + lang = self.get_setting('lang') |
2157 | + if lang: |
2158 | try: |
2159 | - run_cmd('locale-gen', '%s' % self.vm.lang) |
2160 | + run_cmd('locale-gen', '%s' % lang) |
2161 | except VMBuilderException, e: |
2162 | - msg = "locale-gen does not recognize your locale '%s'" % self.vm.lang |
2163 | - raise VMBuilderUserError(msg) |
2164 | - |
2165 | - if getattr(self.vm, 'ec2', False): |
2166 | - self.get_ec2_kernel() |
2167 | - self.get_ec2_ramdisk() |
2168 | - self.apply_ec2_settings() |
2169 | + raise VMBuilderUserError("Unrecognised locale: '%s'" % (lang, )) |
2170 | + |
2171 | +# FIXME |
2172 | +# if getattr(self.vm, 'ec2', False): |
2173 | +# self.get_ec2_kernel() |
2174 | +# self.get_ec2_ramdisk() |
2175 | +# self.apply_ec2_settings() |
2176 | + |
2177 | + def bootstrap(self): |
2178 | + self.suite.debootstrap() |
2179 | + self.suite.pre_install() |
2180 | + |
2181 | + def configure_os(self): |
2182 | + self.suite.install_sources_list() |
2183 | + self.suite.install_apt_proxy() |
2184 | + self.suite.create_devices() |
2185 | + self.suite.prevent_daemons_starting() |
2186 | + self.suite.mount_dev_proc() |
2187 | + self.suite.install_extras() |
2188 | + self.suite.create_initial_user() |
2189 | + self.suite.install_authorized_keys() |
2190 | + self.suite.config_host_and_domainname() |
2191 | + self.suite.set_timezone() |
2192 | + self.suite.install_sources_list(final=True) |
2193 | + self.suite.run_in_target('apt-get', 'clean'); |
2194 | + self.suite.unmount_volatile() |
2195 | + self.suite.unmount_proc() |
2196 | + self.suite.unmount_dev_pts() |
2197 | + self.suite.unmount_dev() |
2198 | + self.suite.unprevent_daemons_starting() |
2199 | + |
2200 | + def configure_networking(self, nics): |
2201 | + self.suite.config_interfaces(nics) |
2202 | + |
2203 | + def configure_mounting(self, disks, filesystems): |
2204 | + self.suite.install_fstab(disks, filesystems) |
2205 | |
2206 | def install(self, destdir): |
2207 | self.destdir = destdir |
2208 | @@ -156,37 +186,42 @@ |
2209 | def use_virtio_net(self): |
2210 | return self.suite.virtio_net |
2211 | |
2212 | - def install_bootloader_cleanup(self): |
2213 | - self.vm.cancel_cleanup(self.install_bootloader_cleanup) |
2214 | - tmpdir = '%s/tmp/vmbuilder-grub' % self.destdir |
2215 | + def install_bootloader_cleanup(self, chroot_dir): |
2216 | + self.context.cancel_cleanup(self.install_bootloader_cleanup) |
2217 | + tmpdir = '%s/tmp/vmbuilder-grub' % chroot_dir |
2218 | for disk in os.listdir(tmpdir): |
2219 | if disk != 'device.map': |
2220 | run_cmd('umount', os.path.join(tmpdir, disk)) |
2221 | shutil.rmtree(tmpdir) |
2222 | |
2223 | - def install_bootloader(self): |
2224 | + def install_kernel(self, destdir): |
2225 | + self.suite.install_kernel(destdir) |
2226 | + |
2227 | + def install_bootloader(self, chroot_dir, disks): |
2228 | tmpdir = '/tmp/vmbuilder-grub' |
2229 | - os.makedirs('%s%s' % (self.destdir, tmpdir)) |
2230 | - self.vm.add_clean_cb(self.install_bootloader_cleanup) |
2231 | + os.makedirs('%s%s' % (chroot_dir, tmpdir)) |
2232 | + self.context.add_clean_cb(self.install_bootloader_cleanup) |
2233 | devmapfile = os.path.join(tmpdir, 'device.map') |
2234 | - devmap = open('%s%s' % (self.destdir, devmapfile), 'w') |
2235 | - for (disk, id) in zip(self.vm.disks, range(len(self.vm.disks))): |
2236 | + devmap = open('%s%s' % (chroot_dir, devmapfile), 'w') |
2237 | + for (disk, id) in zip(disks, range(len(disks))): |
2238 | new_filename = os.path.join(tmpdir, os.path.basename(disk.filename)) |
2239 | - open('%s%s' % (self.destdir, new_filename), 'w').close() |
2240 | - run_cmd('mount', '--bind', disk.filename, '%s%s' % (self.destdir, new_filename)) |
2241 | + open('%s%s' % (chroot_dir, new_filename), 'w').close() |
2242 | + run_cmd('mount', '--bind', disk.filename, '%s%s' % (chroot_dir, new_filename)) |
2243 | devmap.write("(hd%d) %s\n" % (id, new_filename)) |
2244 | devmap.close() |
2245 | + self.suite.install_grub(chroot_dir) |
2246 | self.run_in_target('grub', '--device-map=%s' % devmapfile, '--batch', stdin='''root (hd0,0) |
2247 | setup (hd0) |
2248 | -EOT''') |
2249 | - self.install_bootloader_cleanup() |
2250 | +EOT''') |
2251 | + self.suite.install_menu_lst(disks) |
2252 | + self.install_bootloader_cleanup(chroot_dir) |
2253 | |
2254 | def xen_kernel_version(self): |
2255 | if self.suite.xen_kernel_flavour: |
2256 | # if this is ec2, do not call rmadison. |
2257 | # this could be replaced with a method to get most recent |
2258 | # stable kernel, but really, this is not used at all for ec2 |
2259 | - if hasattr(self.vm, 'ec2') and self.vm.ec2: |
2260 | + if hasattr(self.vm, 'ec2') and self.context.ec2: |
2261 | logging.debug("selecting ec2 kernel") |
2262 | self.xen_kernel = "2.6.ec2-kernel" |
2263 | return self.xen_kernel |
2264 | @@ -197,7 +232,7 @@ |
2265 | for line in rmad.splitlines(): |
2266 | sline = line.split('|') |
2267 | |
2268 | - if sline[2].strip().startswith(self.vm.suite): |
2269 | + if sline[2].strip().startswith(self.context.suite): |
2270 | vt = sline[1].strip().split('.') |
2271 | for i in range(4): |
2272 | if int(vt[i]) > int(version[i]): |
2273 | @@ -205,7 +240,7 @@ |
2274 | break |
2275 | |
2276 | if version[0] == '0': |
2277 | - raise VMBuilderException('Something is wrong, no valid xen kernel for the suite %s found by rmadison' % self.vm.suite) |
2278 | + raise VMBuilderException('Something is wrong, no valid xen kernel for the suite %s found by rmadison' % self.context.suite) |
2279 | |
2280 | self.xen_kernel = '%s.%s.%s-%s' % (version[0],version[1],version[2],version[3]) |
2281 | return self.xen_kernel |
2282 | @@ -224,13 +259,13 @@ |
2283 | |
2284 | def get_ec2_kernel(self): |
2285 | if self.suite.ec2_kernel_info: |
2286 | - return self.suite.ec2_kernel_info[self.vm.arch] |
2287 | + return self.suite.ec2_kernel_info[self.context.arch] |
2288 | else: |
2289 | raise VMBuilderUserError('EC2 is not supported for the suite selected') |
2290 | |
2291 | def get_ec2_ramdisk(self): |
2292 | if self.suite.ec2_ramdisk_info: |
2293 | - return self.suite.ec2_ramdisk_info[self.vm.arch] |
2294 | + return self.suite.ec2_ramdisk_info[self.context.arch] |
2295 | else: |
2296 | raise VMBuilderUserError('EC2 is not supported for the suite selected') |
2297 | |
2298 | @@ -240,4 +275,7 @@ |
2299 | def apply_ec2_settings(self): |
2300 | return self.suite.apply_ec2_settings() |
2301 | |
2302 | + def has_256_bit_inode_ext3_support(self): |
2303 | + return self.suite.has_256_bit_inode_ext3_support() |
2304 | + |
2305 | register_distro(Ubuntu) |
2306 | |
2307 | === modified file 'VMBuilder/plugins/ubuntu/edgy.py' |
2308 | --- VMBuilder/plugins/ubuntu/edgy.py 2009-08-07 16:07:55 +0000 |
2309 | +++ VMBuilder/plugins/ubuntu/edgy.py 2010-02-18 16:03:14 +0000 |
2310 | @@ -31,7 +31,7 @@ |
2311 | disk_prefix = 'sd' |
2312 | |
2313 | def mangle_grub_menu_lst(self): |
2314 | - bootdev = disk.bootpart(self.vm.disks) |
2315 | + bootdev = disk.bootpart(self.context.disks) |
2316 | run_cmd('sed', '-ie', 's/^# kopt=root=\([^ ]*\)\(.*\)/# kopt=root=UUID=%s\\2/g' % bootdev.fs.uuid, '%s/boot/grub/menu.lst' % self.destdir) |
2317 | run_cmd('sed', '-ie', 's/^# groot.*/# groot %s/g' % bootdev.get_grub_id(), '%s/boot/grub/menu.lst' % self.destdir) |
2318 | run_cmd('sed', '-ie', '/^# kopt_2_6/ d', '%s/boot/grub/menu.lst' % self.destdir) |
2319 | @@ -42,7 +42,7 @@ |
2320 | # <file system> <mount point> <type> <options> <dump> <pass> |
2321 | proc /proc proc defaults 0 0 |
2322 | ''' |
2323 | - parts = disk.get_ordered_partitions(self.vm.disks) |
2324 | + parts = disk.get_ordered_partitions(self.context.disks) |
2325 | for part in parts: |
2326 | retval += "UUID=%-40s %15s %7s %15s %d %d\n" % (part.fs.uuid, part.fs.mntpnt, part.fs.fstab_fstype(), part.fs.fstab_options(), 0, 0) |
2327 | return retval |
2328 | @@ -58,9 +58,9 @@ |
2329 | self.copy_to_target('/etc/default/console-setup', '/etc/default/console-setup') |
2330 | self.run_in_target('dpkg-reconfigure', '-fnoninteractive', '-pcritical', 'tzdata') |
2331 | self.run_in_target('locale-gen', 'en_US') |
2332 | - if self.vm.lang: |
2333 | - self.run_in_target('locale-gen', self.vm.lang) |
2334 | - self.install_from_template('/etc/default/locale', 'locale', { 'lang' : self.vm.lang }) |
2335 | + if self.context.lang: |
2336 | + self.run_in_target('locale-gen', self.context.lang) |
2337 | + self.install_from_template('/etc/default/locale', 'locale', { 'lang' : self.context.lang }) |
2338 | self.run_in_target('dpkg-reconfigure', '-fnoninteractive', '-pcritical', 'locales') |
2339 | if have_cs: |
2340 | self.run_in_target('dpkg-reconfigure', '-fnoninteractive', '-pcritical', 'console-setup') |
2341 | |
2342 | === modified file 'VMBuilder/plugins/ubuntu/hardy.py' |
2343 | --- VMBuilder/plugins/ubuntu/hardy.py 2009-11-05 01:42:05 +0000 |
2344 | +++ VMBuilder/plugins/ubuntu/hardy.py 2010-02-18 16:03:14 +0000 |
2345 | @@ -25,21 +25,21 @@ |
2346 | ec2_ramdisk_info = { 'i386' : 'ari-6c709705', 'amd64' : 'ari-61709708' } |
2347 | |
2348 | def apply_ec2_settings(self): |
2349 | - self.vm.addpkg += ['ec2-init', |
2350 | + self.context.addpkg += ['ec2-init', |
2351 | 'openssh-server', |
2352 | 'ec2-modules', |
2353 | 'standard^', |
2354 | 'ec2-ami-tools', |
2355 | 'update-motd'] |
2356 | |
2357 | - if not self.vm.ppa: |
2358 | - self.vm.ppa = [] |
2359 | + if not self.context.ppa: |
2360 | + self.context.ppa = [] |
2361 | |
2362 | - self.vm.ppa += ['ubuntu-on-ec2/ppa'] |
2363 | + self.context.ppa += ['ubuntu-on-ec2/ppa'] |
2364 | |
2365 | def install_ec2(self): |
2366 | |
2367 | - if self.vm.arch == 'i386': |
2368 | + if self.context.arch == 'i386': |
2369 | self.run_in_target('apt-get' ,'--force-yes', '-y', 'install', 'libc6-xen') |
2370 | self.run_in_target('apt-get','--purge','--force-yes', '-y', 'remove', 'libc6-i686') |
2371 | self.install_from_template('/etc/ld.so.conf.d/libc6-xen.conf', 'xen-ld-so-conf') |
2372 | @@ -54,3 +54,6 @@ |
2373 | |
2374 | def xen_ramdisk_path(self): |
2375 | return '/boot/initrd.img-2.6.24-19-xen' |
2376 | + |
2377 | + def has_256_bit_inode_ext3_support(self): |
2378 | + return True |
2379 | |
2380 | === modified file 'VMBuilder/plugins/ubuntu/intrepid.py' |
2381 | --- VMBuilder/plugins/ubuntu/intrepid.py 2009-11-05 01:42:05 +0000 |
2382 | +++ VMBuilder/plugins/ubuntu/intrepid.py 2010-02-18 16:03:14 +0000 |
2383 | @@ -40,7 +40,7 @@ |
2384 | self.install_from_template('/etc/ec2-init/is-compat-env', 'is-compat-env') |
2385 | |
2386 | def mangle_grub_menu_lst(self): |
2387 | - bootdev = disk.bootpart(self.vm.disks) |
2388 | + bootdev = disk.bootpart(self.context.disks) |
2389 | run_cmd('sed', '-ie', 's/^# kopt=root=\([^ ]*\)\(.*\)/# kopt=root=UUID=%s\\2/g' % bootdev.fs.uuid, '%s/boot/grub/menu.lst' % self.destdir) |
2390 | run_cmd('sed', '-ie', 's/^# groot.*/# groot=%s/g' % bootdev.fs.uuid, '%s/boot/grub/menu.lst' % self.destdir) |
2391 | run_cmd('sed', '-ie', '/^# kopt_2_6/ d', '%s/boot/grub/menu.lst' % self.destdir) |
2392 | |
2393 | === modified file 'VMBuilder/plugins/ubuntu/jaunty.py' |
2394 | --- VMBuilder/plugins/ubuntu/jaunty.py 2009-09-26 17:39:48 +0000 |
2395 | +++ VMBuilder/plugins/ubuntu/jaunty.py 2010-02-18 16:03:14 +0000 |
2396 | @@ -34,9 +34,9 @@ |
2397 | self.install_from_template('/etc/ec2-init/is-compat-env', 'is-compat-env') |
2398 | self.run_in_target('chmod', '755', '/etc/update-motd.d/51_update-motd') |
2399 | |
2400 | - def mangle_grub_menu_lst(self): |
2401 | - bootdev = disk.bootpart(self.vm.disks) |
2402 | - run_cmd('sed', '-ie', 's/^# kopt=root=\([^ ]*\)\(.*\)/# kopt=root=UUID=%s\\2/g' % bootdev.fs.uuid, '%s/boot/grub/menu.lst' % self.destdir) |
2403 | - run_cmd('sed', '-ie', 's/^# groot.*/# groot=%s/g' % bootdev.fs.uuid, '%s/boot/grub/menu.lst' % self.destdir) |
2404 | - run_cmd('sed', '-ie', '/^# kopt_2_6/ d', '%s/boot/grub/menu.lst' % self.destdir) |
2405 | + def mangle_grub_menu_lst(self, disks): |
2406 | + bootdev = disk.bootpart(disks) |
2407 | + run_cmd('sed', '-ie', 's/^# kopt=root=\([^ ]*\)\(.*\)/# kopt=root=UUID=%s\\2/g' % bootdev.fs.uuid, '%s/boot/grub/menu.lst' % self.context.chroot_dir) |
2408 | + run_cmd('sed', '-ie', 's/^# groot.*/# groot=%s/g' % bootdev.fs.uuid, '%s/boot/grub/menu.lst' % self.context.chroot_dir) |
2409 | + run_cmd('sed', '-ie', '/^# kopt_2_6/ d', '%s/boot/grub/menu.lst' % self.context.chroot_dir) |
2410 | |
2411 | |
2412 | === modified file 'VMBuilder/plugins/ubuntu/karmic.py' |
2413 | --- VMBuilder/plugins/ubuntu/karmic.py 2009-09-25 19:14:04 +0000 |
2414 | +++ VMBuilder/plugins/ubuntu/karmic.py 2010-02-18 16:03:14 +0000 |
2415 | @@ -24,8 +24,8 @@ |
2416 | |
2417 | class Karmic(Jaunty): |
2418 | def apply_ec2_settings(self): |
2419 | - self.vm.addpkg += ['standard^', |
2420 | + self.context.addpkg += ['standard^', |
2421 | 'uec^'] |
2422 | |
2423 | def pre_install(self): |
2424 | - self.vm.install_file('/etc/hosts', contents='') |
2425 | + self.context.install_file('/etc/hosts', contents='') |
2426 | |
2427 | === modified file 'VMBuilder/plugins/ubuntu/suite.py' |
2428 | --- VMBuilder/plugins/ubuntu/suite.py 2009-06-10 13:40:41 +0000 |
2429 | +++ VMBuilder/plugins/ubuntu/suite.py 2010-02-18 16:03:14 +0000 |
2430 | @@ -24,8 +24,8 @@ |
2431 | import sys |
2432 | |
2433 | class Suite(object): |
2434 | - def __init__(self, vm): |
2435 | - self.vm = vm |
2436 | + def __init__(self, context): |
2437 | + self.context = context |
2438 | self.isodir = '/media/vmbuilder_inst_image' |
2439 | self.iso_mounted = False |
2440 | |
2441 | |
2442 | === modified file 'VMBuilder/plugins/ubuntu/templates/dapper_fstab.tmpl' |
2443 | --- VMBuilder/plugins/ubuntu/templates/dapper_fstab.tmpl 2008-09-18 09:11:09 +0000 |
2444 | +++ VMBuilder/plugins/ubuntu/templates/dapper_fstab.tmpl 2010-02-18 16:03:14 +0000 |
2445 | @@ -2,6 +2,7 @@ |
2446 | # |
2447 | # <file system> <mount point> <type> <options> <dump> <pass> |
2448 | proc /proc proc defaults 0 0 |
2449 | +#* |
2450 | #for $part in $parts |
2451 | #echo '/dev/%s%-40s %-15s %-7s %-15s %d %d\n' % ($prefix, part.get_suffix(), part.mntpnt, part.fs.fstab_fstype(), part.fs.fstab_options(), 0, 0) |
2452 | #* |
2453 | |
2454 | === modified file 'VMBuilder/plugins/virtualbox/vm.py' |
2455 | --- VMBuilder/plugins/virtualbox/vm.py 2009-06-10 13:40:41 +0000 |
2456 | +++ VMBuilder/plugins/virtualbox/vm.py 2010-02-18 16:03:14 +0000 |
2457 | @@ -32,25 +32,25 @@ |
2458 | arg = 'vbox' |
2459 | |
2460 | def register_options(self): |
2461 | - group = self.vm.setting_group('VirtualBox options') |
2462 | + group = self.context.setting_group('VirtualBox options') |
2463 | group.add_option('--vbox-disk-format', metavar='FORMAT', default='vdi', help='Desired disk format. Valid options are: vdi vmdk. [default: %default]') |
2464 | - self.vm.register_setting_group(group) |
2465 | + self.context.register_setting_group(group) |
2466 | |
2467 | def finalize(self): |
2468 | self.imgs = [] |
2469 | - for disk in self.vm.disks: |
2470 | - img_path = disk.convert(self.vm.destdir, self.vm.vbox_disk_format) |
2471 | + for disk in self.context.disks: |
2472 | + img_path = disk.convert(self.context.destdir, self.context.vbox_disk_format) |
2473 | self.imgs.append(img_path) |
2474 | - self.vm.result_files.append(img_path) |
2475 | + self.context.result_files.append(img_path) |
2476 | |
2477 | def deploy(self): |
2478 | - vm_deploy_script = VMBuilder.util.render_template('virtualbox', self.vm, 'vm_deploy_script', { 'os_type' : self.vm.distro.__class__.__name__, 'vm_name' : self.vm.hostname, 'vm_disks' : self.imgs, 'memory' : self.vm.mem }) |
2479 | + vm_deploy_script = VMBuilder.util.render_template('virtualbox', self.context, 'vm_deploy_script', { 'os_type' : self.context.distro.__class__.__name__, 'vm_name' : self.context.hostname, 'vm_disks' : self.imgs, 'memory' : self.context.mem }) |
2480 | |
2481 | - script_file = '%s/deploy_%s.sh' % (self.vm.destdir, self.vm.hostname) |
2482 | + script_file = '%s/deploy_%s.sh' % (self.context.destdir, self.context.hostname) |
2483 | fp = open(script_file, 'w') |
2484 | fp.write(vm_deploy_script) |
2485 | fp.close() |
2486 | os.chmod(script_file, stat.S_IRWXU | stat.S_IRGRP | stat.S_IROTH) |
2487 | - self.vm.result_files.append(script_file) |
2488 | + self.context.result_files.append(script_file) |
2489 | |
2490 | register_hypervisor(VirtualBox) |
2491 | |
2492 | === modified file 'VMBuilder/plugins/vmware/vm.py' |
2493 | --- VMBuilder/plugins/vmware/vm.py 2009-06-10 13:40:41 +0000 |
2494 | +++ VMBuilder/plugins/vmware/vm.py 2010-02-18 16:03:14 +0000 |
2495 | @@ -33,23 +33,23 @@ |
2496 | |
2497 | def finalize(self): |
2498 | self.imgs = [] |
2499 | - for disk in self.vm.disks: |
2500 | - img_path = disk.convert(self.vm.destdir, self.filetype) |
2501 | + for disk in self.context.disks: |
2502 | + img_path = disk.convert(self.context.destdir, self.filetype) |
2503 | self.imgs.append(img_path) |
2504 | - self.vm.result_files.append(img_path) |
2505 | + self.context.result_files.append(img_path) |
2506 | |
2507 | def disks(self): |
2508 | - return self.vm.disks |
2509 | + return self.context.disks |
2510 | |
2511 | def deploy(self): |
2512 | - vmdesc = VMBuilder.util.render_template('vmware', self.vm, self.vmxtemplate, { 'disks' : self.disks(), 'vmhwversion' : self.vmhwversion, 'cpus' : self.vm.cpus, 'mem' : self.vm.mem, 'hostname' : self.vm.hostname, 'arch' : self.vm.arch, 'guestos' : (self.vm.arch == 'amd64' and 'ubuntu-64' or 'ubuntu') }) |
2513 | + vmdesc = VMBuilder.util.render_template('vmware', self.context, self.vmxtemplate, { 'disks' : self.disks(), 'vmhwversion' : self.vmhwversion, 'cpus' : self.context.cpus, 'mem' : self.context.mem, 'hostname' : self.context.hostname, 'arch' : self.context.arch, 'guestos' : (self.context.arch == 'amd64' and 'ubuntu-64' or 'ubuntu') }) |
2514 | |
2515 | - vmx = '%s/%s.vmx' % (self.vm.destdir, self.vm.hostname) |
2516 | + vmx = '%s/%s.vmx' % (self.context.destdir, self.context.hostname) |
2517 | fp = open(vmx, 'w') |
2518 | fp.write(vmdesc) |
2519 | fp.close() |
2520 | os.chmod(vmx, stat.S_IRWXU | stat.S_IRWXU | stat.S_IROTH | stat.S_IXOTH) |
2521 | - self.vm.result_files.append(vmx) |
2522 | + self.context.result_files.append(vmx) |
2523 | |
2524 | class VMWareWorkstation6(VMWare): |
2525 | name = 'VMWare Workstation 6' |
2526 | @@ -72,33 +72,33 @@ |
2527 | |
2528 | def finalize(self): |
2529 | self.imgs = [] |
2530 | - for disk in self.vm.disks: |
2531 | + for disk in self.context.disks: |
2532 | |
2533 | # Move raw image to <imagename>-flat.vmdk |
2534 | diskfilename = os.path.basename(disk.filename) |
2535 | if '.' in diskfilename: |
2536 | diskfilename = diskfilename[:diskfilename.rindex('.')] |
2537 | |
2538 | - flat = '%s/%s-flat.vmdk' % (self.vm.destdir, diskfilename) |
2539 | + flat = '%s/%s-flat.vmdk' % (self.context.destdir, diskfilename) |
2540 | self.vmdks.append(diskfilename) |
2541 | |
2542 | move(disk.filename, flat) |
2543 | |
2544 | - self.vm.result_files.append(flat) |
2545 | + self.context.result_files.append(flat) |
2546 | |
2547 | # Create disk descriptor file |
2548 | sectorTotal = disk.size * 2048 |
2549 | sector = int(floor(sectorTotal / 16065)) # pseudo geometry |
2550 | |
2551 | - diskdescriptor = VMBuilder.util.render_template('vmware', self.vm, 'flat.vmdk', { 'adaptertype' : self.adaptertype, 'sectors' : sector, 'diskname' : os.path.basename(flat), 'disksize' : sectorTotal }) |
2552 | - vmdk = '%s/%s.vmdk' % (self.vm.destdir, diskfilename) |
2553 | + diskdescriptor = VMBuilder.util.render_template('vmware', self.context, 'flat.vmdk', { 'adaptertype' : self.adaptertype, 'sectors' : sector, 'diskname' : os.path.basename(flat), 'disksize' : sectorTotal }) |
2554 | + vmdk = '%s/%s.vmdk' % (self.context.destdir, diskfilename) |
2555 | |
2556 | fp = open(vmdk, 'w') |
2557 | fp.write(diskdescriptor) |
2558 | fp.close() |
2559 | os.chmod(vmdk, stat.S_IRWXU | stat.S_IRWXU | stat.S_IROTH | stat.S_IXOTH) |
2560 | |
2561 | - self.vm.result_files.append(vmdk) |
2562 | + self.context.result_files.append(vmdk) |
2563 | |
2564 | def disks(self): |
2565 | return self.vmdks |
2566 | |
2567 | === modified file 'VMBuilder/plugins/xen/vm.py' |
2568 | --- VMBuilder/plugins/xen/vm.py 2009-06-10 13:40:41 +0000 |
2569 | +++ VMBuilder/plugins/xen/vm.py 2010-02-18 16:03:14 +0000 |
2570 | @@ -31,29 +31,29 @@ |
2571 | needs_bootloader = False |
2572 | |
2573 | def register_options(self): |
2574 | - group = self.vm.setting_group('Xen option') |
2575 | + group = self.context.setting_group('Xen option') |
2576 | group.add_option('--xen-kernel', metavar='PATH', help='Path to the kernel to use (e.g.: /boot/vmlinux-2.6.27-7-server). Default depends on distribution and suite') |
2577 | group.add_option('--xen-ramdisk', metavar='PATH', help='Path to the ramdisk to use (e.g.: /boot/initrd.img-2.6.27-7-server). Default depends on distribution and suite.') |
2578 | - self.vm.register_setting_group(group) |
2579 | + self.context.register_setting_group(group) |
2580 | |
2581 | def finalize(self): |
2582 | destimages = [] |
2583 | - for filesystem in self.vm.filesystems: |
2584 | + for filesystem in self.context.filesystems: |
2585 | if not filesystem.preallocated: |
2586 | - destfile = '%s/%s' % (self.vm.destdir, os.path.basename(filesystem.filename)) |
2587 | + destfile = '%s/%s' % (self.context.destdir, os.path.basename(filesystem.filename)) |
2588 | logging.info('Moving %s to %s' % (filesystem.filename, destfile)) |
2589 | - self.vm.result_files.append(destfile) |
2590 | + self.context.result_files.append(destfile) |
2591 | run_cmd('cp', '--sparse=always', filesystem.filename, destfile) |
2592 | os.unlink(filesystem.filename) |
2593 | filesystem.filename = os.path.abspath(destfile) |
2594 | destimages.append(destfile) |
2595 | |
2596 | - if not self.vm.xen_kernel: |
2597 | - self.vm.xen_kernel = self.vm.distro.xen_kernel_path() |
2598 | - if not self.vm.xen_ramdisk: |
2599 | - self.vm.xen_ramdisk = self.vm.distro.xen_ramdisk_path() |
2600 | + if not self.context.xen_kernel: |
2601 | + self.context.xen_kernel = self.context.distro.xen_kernel_path() |
2602 | + if not self.context.xen_ramdisk: |
2603 | + self.context.xen_ramdisk = self.context.distro.xen_ramdisk_path() |
2604 | |
2605 | - xenconf = '%s/xen.conf' % self.vm.destdir |
2606 | + xenconf = '%s/xen.conf' % self.context.destdir |
2607 | fp = open(xenconf, 'w') |
2608 | fp.write(""" |
2609 | # Configuration file for the Xen instance %s, created |
2610 | @@ -78,13 +78,13 @@ |
2611 | |
2612 | extra = 'xencons=tty console=tty1 console=hvc0' |
2613 | |
2614 | -""" % (self.vm.name, |
2615 | - self.vm.xen_kernel, |
2616 | - self.vm.xen_ramdisk, |
2617 | - self.vm.mem, |
2618 | +""" % (self.context.name, |
2619 | + self.context.xen_kernel, |
2620 | + self.context.xen_ramdisk, |
2621 | + self.context.mem, |
2622 | ',\n'.join(["'tap:aio:%s,xvda%d,w'" % (os.path.abspath(img), id+1) for (img, id) in zip(destimages, range(len(destimages)))]), |
2623 | - self.vm.name)) |
2624 | + self.context.name)) |
2625 | fp.close() |
2626 | - self.vm.result_files.append(xenconf) |
2627 | + self.context.result_files.append(xenconf) |
2628 | |
2629 | register_hypervisor(Xen) |
2630 | |
2631 | === modified file 'VMBuilder/util.py' |
2632 | --- VMBuilder/util.py 2009-09-16 15:27:15 +0000 |
2633 | +++ VMBuilder/util.py 2010-02-18 16:03:14 +0000 |
2634 | @@ -21,10 +21,10 @@ |
2635 | import logging |
2636 | import os |
2637 | import os.path |
2638 | -import pwd |
2639 | import select |
2640 | import subprocess |
2641 | import sys |
2642 | +import tempfile |
2643 | import time |
2644 | from exception import VMBuilderException, VMBuilderUserError |
2645 | |
2646 | @@ -135,19 +135,6 @@ |
2647 | raise VMBuilderException, "Process (%s) returned %d. stdout: %s, stderr: %s" % (args.__repr__(), status, stdout, stderr) |
2648 | return stdout |
2649 | |
2650 | -def give_to_caller(path): |
2651 | - """ |
2652 | - Change ownership of file to $SUDO_USER. |
2653 | - |
2654 | - @type path: string |
2655 | - @param path: file or directory to give to $SUDO_USER |
2656 | - """ |
2657 | - |
2658 | - if 'SUDO_USER' in os.environ: |
2659 | - logging.debug('Changing ownership of %s to %s' % (path, os.environ['SUDO_USER'])) |
2660 | - (uid, gid) = pwd.getpwnam(os.environ['SUDO_USER'])[2:4] |
2661 | - os.chown(path, uid, gid) |
2662 | - |
2663 | def checkroot(): |
2664 | """ |
2665 | Check if we're running as root, and bail out if we're not. |
2666 | @@ -156,18 +143,6 @@ |
2667 | if os.geteuid() != 0: |
2668 | raise VMBuilderUserError("This script must be run as root (e.g. via sudo)") |
2669 | |
2670 | -def fix_ownership(files): |
2671 | - """ |
2672 | - Goes through files and fixes their ownership of them. |
2673 | - |
2674 | - @type files: list |
2675 | - @param files: files whose ownership should be fixed up (currently |
2676 | - simply calls L{give_to_caller}) |
2677 | - |
2678 | - """ |
2679 | - for file in files: |
2680 | - give_to_caller(file) |
2681 | - |
2682 | def render_template(plugin, vm, tmplname, context=None): |
2683 | # Import here to avoid having to build-dep on python-cheetah |
2684 | from Cheetah.Template import Template |
2685 | @@ -180,8 +155,8 @@ |
2686 | os.path.dirname(__file__) + '/plugins/%s/templates', |
2687 | '/etc/vmbuilder/%s'] |
2688 | |
2689 | - if vm.templates: |
2690 | - tmpldirs.insert(0,'%s/%%s' % vm.templates) |
2691 | +# if vm.templates: |
2692 | +# tmpldirs.insert(0,'%s/%%s' % vm.templates) |
2693 | |
2694 | tmpldirs = [dir % plugin for dir in tmpldirs] |
2695 | |
2696 | @@ -194,3 +169,30 @@ |
2697 | return output |
2698 | |
2699 | raise VMBuilderException('Template %s.tmpl not found in any of %s' % (tmplname, ', '.join(tmpldirs))) |
2700 | + |
2701 | +def call_hooks(context, func, *args, **kwargs): |
2702 | + logging.debug('Calling hook: %s(args=%r, kwargs=%r)' % (func, args, kwargs)) |
2703 | + for plugin in context.plugins: |
2704 | + logging.debug('Calling %s method in %s plugin.' % (func, plugin.__module__)) |
2705 | + getattr(plugin, func, log_no_such_method)(*args, **kwargs) |
2706 | + |
2707 | + logging.debug('Calling %s method in context plugin %s.' % (func, context.__module__)) |
2708 | + getattr(context, func, log_no_such_method)(*args, **kwargs) |
2709 | + |
2710 | +def log_no_such_method(*args, **kwargs): |
2711 | + logging.debug('No such method') |
2712 | + return |
2713 | + |
2714 | +def tmpfile(suffix='', keep=True): |
2715 | + (fd, filename) = tempfile.mkstemp(suffix=suffix) |
2716 | + os.close(fd) |
2717 | + if not keep: |
2718 | + os.unlink(filename) |
2719 | + return filename |
2720 | + |
2721 | +def tmpdir(suffix='', keep=True): |
2722 | + dir = tempfile.mkdtemp(suffix=suffix) |
2723 | + if not keep: |
2724 | + os.rmdir(dir) |
2725 | + return dir |
2726 | + |
2727 | |
2728 | === modified file 'VMBuilder/vm.py' |
2729 | --- VMBuilder/vm.py 2010-02-02 15:36:35 +0000 |
2730 | +++ VMBuilder/vm.py 2010-02-18 16:03:14 +0000 |
2731 | @@ -92,34 +92,6 @@ |
2732 | |
2733 | self.add_clean_cmd('rm', log.logfile) |
2734 | |
2735 | - def get_version_info(self): |
2736 | - import vcsversion |
2737 | - info = vcsversion.version_info |
2738 | - info['major'] = 0 |
2739 | - info['minor'] = 11 |
2740 | - info['micro'] = 3 |
2741 | - return info |
2742 | - |
2743 | - def cleanup(self): |
2744 | - logging.info("Cleaning up") |
2745 | - while len(self._cleanup_cbs) > 0: |
2746 | - self._cleanup_cbs.pop(0)() |
2747 | - |
2748 | - def add_clean_cb(self, cb): |
2749 | - self._cleanup_cbs.insert(0, cb) |
2750 | - |
2751 | - def add_clean_cmd(self, *argv, **kwargs): |
2752 | - cb = lambda : util.run_cmd(*argv, **kwargs) |
2753 | - self.add_clean_cb(cb) |
2754 | - return cb |
2755 | - |
2756 | - def cancel_cleanup(self, cb): |
2757 | - try: |
2758 | - self._cleanup_cbs.remove(cb) |
2759 | - except ValueError, e: |
2760 | - # Wasn't in there. No worries. |
2761 | - pass |
2762 | - |
2763 | def distro_help(self): |
2764 | return 'Distro. Valid options: %s' % " ".join(VMBuilder.distros.keys()) |
2765 | |
2766 | @@ -149,18 +121,6 @@ |
2767 | self.register_setting('-m', '--mem', type='int', default=128, help='Assign MEM megabytes of memory to the guest vm. [default: %default]') |
2768 | self.register_setting('--cpus', type='int', default=1, help='Number of virtual CPU\'s. [default: %default]') |
2769 | |
2770 | - group = self.setting_group('Network related options') |
2771 | - domainname = '.'.join(socket.gethostbyname_ex(socket.gethostname())[0].split('.')[1:]) or "defaultdomain" |
2772 | - group.add_option('--domain', metavar='DOMAIN', default=domainname, help='Set DOMAIN as the domain name of the guest [default: The domain of the machine running this script: %default].') |
2773 | - group.add_option('--ip', metavar='ADDRESS', default='dhcp', help='IP address in dotted form [default: %default].') |
2774 | - group.add_option('--mac', metavar='VALUE', help='MAC address of the guest [default: one will be automatically generated on first run].') |
2775 | - group.add_option('--mask', metavar='VALUE', help='IP mask in dotted form [default: based on ip setting]. Ignored if --ip is not specified.') |
2776 | - group.add_option('--net', metavar='ADDRESS', help='IP net address in dotted form [default: based on ip setting]. Ignored if --ip is not specified.') |
2777 | - group.add_option('--bcast', metavar='VALUE', help='IP broadcast in dotted form [default: based on ip setting]. Ignored if --ip is not specified.') |
2778 | - group.add_option('--gw', metavar='ADDRESS', help='Gateway (router) address in dotted form [default: based on ip setting (first valid address in the network)]. Ignored if --ip is not specified.') |
2779 | - group.add_option('--dns', metavar='ADDRESS', help='DNS address in dotted form [default: based on ip setting (first valid address in the network)] Ignored if --ip is not specified.') |
2780 | - self.register_setting_group(group) |
2781 | - |
2782 | def add_disk(self, *args, **kwargs): |
2783 | """Adds a disk image to the virtual machine""" |
2784 | disk = Disk(self, *args, **kwargs) |
2785 | @@ -319,28 +279,6 @@ |
2786 | """Creates the working directory for this vm and returns its path""" |
2787 | return tempfile.mkdtemp('', 'vmbuilder', self.tmp) |
2788 | |
2789 | - def mount_partitions(self): |
2790 | - """Mounts all the vm's partitions and filesystems below .rootmnt""" |
2791 | - logging.info('Mounting target filesystems') |
2792 | - fss = disk.get_ordered_filesystems(self) |
2793 | - for fs in fss: |
2794 | - fs.mount() |
2795 | - self.distro.post_mount(fs) |
2796 | - |
2797 | - self.fsmounted = True |
2798 | - |
2799 | - def umount_partitions(self): |
2800 | - """Unmounts all the vm's partitions and filesystems""" |
2801 | - logging.info('Unmounting target filesystem') |
2802 | - fss = VMBuilder.disk.get_ordered_filesystems(self) |
2803 | - fss.reverse() |
2804 | - for fs in fss: |
2805 | - fs.umount() |
2806 | - for disk in self.disks: |
2807 | - disk.unmap() |
2808 | - |
2809 | - self.fsmounted = False |
2810 | - |
2811 | def install(self): |
2812 | if self.in_place: |
2813 | self.installdir = self.rootmnt |
2814 | @@ -383,18 +321,6 @@ |
2815 | |
2816 | testnet.close() |
2817 | |
2818 | - def install_file(self, path, contents=None, source=None, mode=None): |
2819 | - fullpath = '%s%s' % (self.installdir, path) |
2820 | - if source and not contents: |
2821 | - shutil.copy(source, fullpath) |
2822 | - else: |
2823 | - fp = open(fullpath, 'w') |
2824 | - fp.write(contents) |
2825 | - fp.close() |
2826 | - if mode: |
2827 | - os.chmod(fullpath, mode) |
2828 | - return fullpath |
2829 | - |
2830 | def create(self): |
2831 | """ |
2832 | The core vm creation method |
2833 | |
2834 | === modified file 'test/disk_tests.py' |
2835 | --- test/disk_tests.py 2009-10-23 09:34:18 +0000 |
2836 | +++ test/disk_tests.py 2010-02-18 16:03:14 +0000 |
2837 | @@ -15,9 +15,36 @@ |
2838 | # |
2839 | # You should have received a copy of the GNU General Public License |
2840 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
2841 | +import os |
2842 | +import stat |
2843 | +import tempfile |
2844 | import unittest |
2845 | |
2846 | -from VMBuilder.disk import parse_size, index_to_devname, devname_to_index |
2847 | +import VMBuilder |
2848 | +from VMBuilder.disk import parse_size, index_to_devname, devname_to_index, Disk |
2849 | +from VMBuilder.exception import VMBuilderUserError |
2850 | + |
2851 | +def get_temp_filename(): |
2852 | + (fd, tmpfile) = tempfile.mkstemp() |
2853 | + os.close(fd) |
2854 | + return tmpfile |
2855 | + |
2856 | +class MockDistro(object): |
2857 | + def has_256_bit_inode_ext3_support(self): |
2858 | + return True |
2859 | + |
2860 | +class MockHypervisor(object): |
2861 | + def __init__(self): |
2862 | + self.disks = [] |
2863 | + self.distro = MockDistro() |
2864 | + |
2865 | + def add_clean_cb(self, *args, **kwargs): |
2866 | + pass |
2867 | + |
2868 | + def add_disk(self, *args, **kwargs): |
2869 | + disk = Disk(self, *args, **kwargs) |
2870 | + self.disks.append(disk) |
2871 | + return disk |
2872 | |
2873 | class TestSizeParser(unittest.TestCase): |
2874 | def test_suffixesAreCaseInsensitive(self): |
2875 | @@ -67,4 +94,171 @@ |
2876 | for i in range(18277): |
2877 | self.assertEqual(i, devname_to_index(index_to_devname(i))) |
2878 | |
2879 | - |
2880 | +class TestDiskPlugin(unittest.TestCase): |
2881 | + def test_detect_size(self): |
2882 | + "detect_size returns the correct size" |
2883 | + from VMBuilder.util import run_cmd |
2884 | + from VMBuilder.disk import detect_size |
2885 | + |
2886 | + tmpfile = get_temp_filename() |
2887 | + try: |
2888 | + # We assume qemu-img is well-behaved |
2889 | + run_cmd('qemu-img', 'create', tmpfile, '5G') |
2890 | + self.assertTrue(detect_size(tmpfile), 5*1024) |
2891 | + |
2892 | + imgdev = run_cmd('losetup', '-f', '--show', tmpfile).strip() |
2893 | + try: |
2894 | + self.assertTrue(detect_size(imgdev), 5*1024) |
2895 | + except: |
2896 | + raise |
2897 | + finally: |
2898 | + run_cmd('losetup', '-d', imgdev) |
2899 | + except: |
2900 | + raise |
2901 | + finally: |
2902 | + os.unlink(tmpfile) |
2903 | + |
2904 | + def test_disk_filename(self): |
2905 | + tmpfile = get_temp_filename() |
2906 | + os.unlink(tmpfile) |
2907 | + |
2908 | + disk = Disk(MockHypervisor(), tmpfile, size='1G') |
2909 | + disk.create() |
2910 | + self.assertTrue(os.path.exists(tmpfile)) |
2911 | + os.unlink(tmpfile) |
2912 | + |
2913 | + def test_disk_size(self): |
2914 | + # parse_size only deals with MB resolution |
2915 | + sizes = [('10G', 10*1024*1024*1024), |
2916 | + ('400M', 400*1024*1024), |
2917 | + ('345', 345*1024*1024), |
2918 | + ('10240k', 10*1024*1024), |
2919 | + ('10250k', 10*1024*1024), |
2920 | + ('10230k', 9*1024*1024)] |
2921 | + |
2922 | + for (sizestr, size) in sizes: |
2923 | + tmpfile = get_temp_filename() |
2924 | + os.unlink(tmpfile) |
2925 | + |
2926 | + disk = Disk(MockHypervisor(), filename=tmpfile, size=sizestr) |
2927 | + disk.create() |
2928 | + actual_size = os.stat(tmpfile)[stat.ST_SIZE] |
2929 | + self.assertEqual(size, actual_size, 'Asked for %s, expected %d, got %d' % (sizestr, size, actual_size)) |
2930 | + os.unlink(tmpfile) |
2931 | + |
2932 | + |
2933 | + def test_disk_no_size_given(self): |
2934 | + tmpname = get_temp_filename() |
2935 | + os.unlink(tmpname) |
2936 | + |
2937 | + self.assertRaises(VMBuilderUserError, Disk, MockHypervisor(), filename=tmpname) |
2938 | + |
2939 | + def test_disk_size_given_file_exists(self): |
2940 | + tmpname = get_temp_filename() |
2941 | + |
2942 | + self.assertRaises(VMBuilderUserError, Disk, MockHypervisor(), filename=tmpname, size='1G') |
2943 | + |
2944 | + def test_existing_image_no_overwrite(self): |
2945 | + tmpfile = get_temp_filename() |
2946 | + |
2947 | + fp = open(tmpfile, 'w') |
2948 | + fp.write('canary') |
2949 | + fp.close() |
2950 | + |
2951 | + disk = Disk(MockHypervisor(), tmpfile) |
2952 | + disk.create() |
2953 | + fp = open(tmpfile, 'r') |
2954 | + self.assertEqual(fp.read(), 'canary') |
2955 | + fp.close() |
2956 | + os.unlink(tmpfile) |
2957 | + |
2958 | +class TestDiskPartitioningPlugin(unittest.TestCase): |
2959 | + def setUp(self): |
2960 | + self.tmpfile = get_temp_filename() |
2961 | + os.unlink(self.tmpfile) |
2962 | + |
2963 | + self.vm = MockHypervisor() |
2964 | + self.disk = self.vm.add_disk(self.tmpfile, size='1G') |
2965 | + self.disk.create() |
2966 | + |
2967 | + def tearDown(self): |
2968 | + os.unlink(self.tmpfile) |
2969 | + |
2970 | + def test_partition_overlap(self): |
2971 | + self.disk.add_part(1, 512, 'ext3', '/') |
2972 | + self.assertRaises(VMBuilderUserError, self.disk.add_part, 512, 512, 'ext3', '/mnt') |
2973 | + |
2974 | + def test_partition_extends_beyond_disk(self): |
2975 | + self.assertRaises(VMBuilderUserError, self.disk.add_part, 512, 514, 'ext3', '/') |
2976 | + |
2977 | + def test_partition_table_empty(self): |
2978 | + from VMBuilder.util import run_cmd |
2979 | + |
2980 | + file_output = run_cmd('file', self.tmpfile) |
2981 | + self.assertEqual('%s: data' % self.tmpfile, file_output.strip()) |
2982 | + self.disk.partition() |
2983 | + file_output = run_cmd('file', self.tmpfile) |
2984 | + self.assertEqual('%s: x86 boot sector, code offset 0xb8' % self.tmpfile, file_output.strip()) |
2985 | + |
2986 | + file_output = run_cmd('parted', '--script', self.tmpfile, 'print') |
2987 | + self.assertEqual('''Model: (file) |
2988 | +Disk %s: 1074MB |
2989 | +Sector size (logical/physical): 512B/512B |
2990 | +Partition Table: msdos |
2991 | + |
2992 | +Number Start End Size Type File system Flags''' % self.tmpfile, file_output.strip()) |
2993 | + |
2994 | + def test_partition_table_nonempty(self): |
2995 | + from VMBuilder.util import run_cmd |
2996 | + |
2997 | + self.disk.add_part(1, 1023, 'ext3', '/') |
2998 | + self.disk.partition() |
2999 | + file_output = run_cmd('parted', '--script', self.tmpfile, 'print') |
3000 | + self.assertEqual('''Model: (file) |
3001 | +Disk %s: 1074MB |
3002 | +Sector size (logical/physical): 512B/512B |
3003 | +Partition Table: msdos |
3004 | + |
3005 | +Number Start End Size Type File system Flags |
3006 | + 1 16.4kB 1023MB 1023MB primary''' % self.tmpfile, file_output.strip()) |
3007 | + |
3008 | + def test_map_partitions(self): |
3009 | + self.disk.add_part(1, 1023, 'ext3', '/') |
3010 | + self.disk.partition() |
3011 | + self.disk.map_partitions() |
3012 | + try: |
3013 | + from VMBuilder.disk import detect_size |
3014 | + self.assertEqual(detect_size(self.disk.partitions[0].filename), 1023000576) |
3015 | + except: |
3016 | + raise |
3017 | + finally: |
3018 | + self.disk.unmap() |
3019 | + |
3020 | + def test_mkfs(self): |
3021 | + self.disk.add_part(1, 1023, 'ext3', '/') |
3022 | + self.disk.partition() |
3023 | + self.disk.map_partitions() |
3024 | + try: |
3025 | + self.disk.mkfs() |
3026 | + except: |
3027 | + raise |
3028 | + finally: |
3029 | + self.disk.unmap() |
3030 | + |
3031 | + def test_get_grub_id(self): |
3032 | + self.assertEqual(self.disk.get_grub_id(), '(hd0)') |
3033 | + |
3034 | + tmpfile2 = get_temp_filename() |
3035 | + os.unlink(tmpfile2) |
3036 | + disk2 = self.vm.add_disk(tmpfile2, '1G') |
3037 | + self.assertEqual(self.disk.get_grub_id(), '(hd0)') |
3038 | + self.assertEqual(disk2.get_grub_id(), '(hd1)') |
3039 | + |
3040 | + def test_get_index(self): |
3041 | + self.assertEqual(self.disk.get_index(), 0) |
3042 | + |
3043 | + tmpfile2 = get_temp_filename() |
3044 | + os.unlink(tmpfile2) |
3045 | + disk2 = self.vm.add_disk(tmpfile2, '1G') |
3046 | + self.assertEqual(self.disk.get_index(), 0) |
3047 | + self.assertEqual(disk2.get_index(), 1) |
3048 | |
3049 | === modified file 'test/plugin_tests.py' |
3050 | --- test/plugin_tests.py 2010-01-27 13:38:16 +0000 |
3051 | +++ test/plugin_tests.py 2010-02-18 16:03:14 +0000 |
3052 | @@ -7,7 +7,7 @@ |
3053 | class VM(VMBuilder.plugins.Plugin): |
3054 | def __init__(self, *args, **kwargs): |
3055 | self._config = {} |
3056 | - self.vm = self |
3057 | + self.context = self |
3058 | |
3059 | class TestPlugin(VMBuilder.plugins.Plugin): |
3060 | pass |
3061 | |
3062 | === modified file 'test/ubuntu_tests.py' |
3063 | --- test/ubuntu_tests.py 2009-10-23 09:27:26 +0000 |
3064 | +++ test/ubuntu_tests.py 2010-02-18 16:03:14 +0000 |
3065 | @@ -33,7 +33,6 @@ |
3066 | def test_invalid_suite_raises_UserError(self): |
3067 | 'Building Ubuntu VMs with an invalid suite raises UserError' |
3068 | |
3069 | - vm = VMBuilder.VM() |
3070 | - vm.suite = 'foo' |
3071 | - ubuntu = Ubuntu(vm) |
3072 | + ubuntu = Ubuntu() |
3073 | + ubuntu.set_setting('suite', 'foo') |
3074 | self.assertRaises(VMBuilderUserError, ubuntu.preflight_check) |
3075 | |
3076 | === modified file 'test/util_tests.py' |
3077 | --- test/util_tests.py 2010-01-22 13:27:16 +0000 |
3078 | +++ test/util_tests.py 2010-02-18 16:03:14 +0000 |
3079 | @@ -20,12 +20,12 @@ |
3080 | class PluginC(Plugin): |
3081 | priority = 15 |
3082 | |
3083 | - saved_plugins = VMBuilder._plugins |
3084 | - VMBuilder._plugins = [] |
3085 | - VMBuilder.register_plugin(PluginA) |
3086 | - VMBuilder.register_plugin(PluginB) |
3087 | - VMBuilder.register_plugin(PluginC) |
3088 | - self.assertEqual(VMBuilder._plugins[0], PluginB) |
3089 | - self.assertEqual(VMBuilder._plugins[1], PluginA) |
3090 | - self.assertEqual(VMBuilder._plugins[2], PluginC) |
3091 | - VMBuilder._plugins = saved_plugins |
3092 | + saved_hypervisor_plugins = VMBuilder._hypervisor_plugins |
3093 | + VMBuilder._hypervisor_plugins = [] |
3094 | + VMBuilder.register_hypervisor_plugin(PluginA) |
3095 | + VMBuilder.register_hypervisor_plugin(PluginB) |
3096 | + VMBuilder.register_hypervisor_plugin(PluginC) |
3097 | + self.assertEqual(VMBuilder._hypervisor_plugins[0], PluginB) |
3098 | + self.assertEqual(VMBuilder._hypervisor_plugins[1], PluginA) |
3099 | + self.assertEqual(VMBuilder._hypervisor_plugins[2], PluginC) |
3100 | + VMBuilder._hypervisor_plugins = saved_hypervisor_plugins |