1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 import ConfigParser
21 from gettext import gettext
22 import logging
23 import os
24 import optparse
25 import textwrap
26 import urllib
27 import VMBuilder
28 import VMBuilder.util as util
29 import VMBuilder.log as log
30 import VMBuilder.disk as disk
31 from VMBuilder.disk import Disk, Filesystem
32 from VMBuilder.exception import VMBuilderException, VMBuilderUserError
33 _ = gettext
34
36 """The VM object has the following attributes of relevance to plugins:
37
38 distro: A distro object, representing the distro running in the vm
39
40 disks: The disk images for the vm.
41 filesystems: The filesystem images for the vm.
42
43 result_files: A list of the files that make up the entire vm.
44 The ownership of these files will be fixed up.
45
46 optparser: Will be of interest mostly to frontends. Any sort of option
47 a plugin accepts will be represented in the optparser.
48
49
50 """
52 self.hypervisor = None
53 self.distro = None
54
55 self.disks = []
56 self.filesystems = []
57
58 self.result_files = []
59 self.plugins = []
60 self._cleanup_cbs = []
61
62
63 self.destdir = None
64
65 self.workdir = None
66
67 self.rootmnt = None
68
69 self.tmproot = None
70
71 self.fsmounted = False
72
73 self.optparser = _MyOptParser(epilog="ubuntu-vm-builder is Copyright (C) 2007-2009 Canonical Ltd. and written by Soren Hansen <soren@linux2go.dk>.", usage='%prog hypervisor distro [options]')
74 self.optparser.arg_help = (('hypervisor', self.hypervisor_help), ('distro', self.distro_help))
75
76 self.confparser = ConfigParser.SafeConfigParser()
77
78 if conf:
79 if not(os.path.isfile(conf)):
80 raise VMBuilderUserError('The path to the configuration file is not valid: %s.' % conf)
81 else:
82 conf = ''
83
84 self.confparser.read(['/etc/vmbuilder.cfg', os.path.expanduser('~/.vmbuilder.cfg'), conf])
85
86 self._register_base_settings()
87
88 self.add_clean_cmd('rm', log.logfile)
89
92
95
97 return self.optparser.add_option(*args, **kwargs)
98
100 return self.optparser.add_option_group(group)
101
103 return optparse.OptionGroup(self.optparser, *args, **kwargs)
104
106 self.register_setting('-d', '--dest', dest='destdir', help='Specify the destination directory. [default: <hypervisor>-<distro>].')
107 self.register_setting('-c', '--config', type='string', help='Specify a additional configuration file')
108 self.register_setting('--debug', action='callback', callback=log.set_verbosity, help='Show debug information')
109 self.register_setting('-v', '--verbose', action='callback', callback=log.set_verbosity, help='Show progress information')
110 self.register_setting('-q', '--quiet', action='callback', callback=log.set_verbosity, help='Silent operation')
111 self.register_setting('-t', '--tmp', default=os.environ.get('TMPDIR', '/tmp'), help='Use TMP as temporary working space for image generation. Defaults to $TMPDIR if it is defined or /tmp otherwise. [default: %default]')
112 self.register_setting('--templates', metavar='DIR', help='Prepend DIR to template search path.')
113 self.register_setting('-o', '--overwrite', action='store_true', default=False, help='Force overwrite of destination directory if it already exist. [default: %default]')
114 self.register_setting('--in-place', action='store_true', default=False, help='Install directly into the filesystem images. This is needed if your $TMPDIR is nodev and/or nosuid, but will result in slightly larger file system images.')
115 self.register_setting('--tmpfs', metavar="OPTS", help='Use a tmpfs as the working directory, specifying its size or "-" to use tmpfs default (suid,dev,size=1G).')
116 self.register_setting('-m', '--mem', type='int', default=128, help='Assign MEM megabytes of memory to the guest vm. [default: %default]')
117
119 """Adds a disk image to the virtual machine"""
120 disk = Disk(self, *args, **kwargs)
121 self.disks.append(disk)
122 return disk
123
125 """Adds a filesystem to the virtual machine"""
126 fs = Filesystem(self, *args, **kwargs)
127 self.filesystems.append(fs)
128 return fs
129
131 for plugin in self.plugins:
132 getattr(plugin, func)()
133 getattr(self.hypervisor, func)()
134 getattr(self.distro, func)()
135
137 for opt in sum([self.confparser.options(section) for section in self.confparser.sections()], []) + [k for (k,v) in self.confparser.defaults().iteritems()]:
138 if '-' in opt:
139 raise VMBuilderUserError('You specified a "%s" config option in a config file, but that is not valid. Perhaps you meant "%s"?' % (opt, opt.replace('-', '_')))
140
141 self.call_hooks('preflight_check')
142
143
144 if self.mirror:
145 testurl = self.mirror
146 else:
147 testurl = 'http://archive.ubuntu.com/'
148
149 try:
150 logging.debug('Testing access to %s' % testurl)
151 testnet = urllib.urlopen(testurl)
152 except IOError:
153 raise VMBuilderUserError('Could not connect to %s. Please check your connectivity and try again.' % testurl)
154
155 testnet.close()
156
158 """
159 The core vm creation method
160
161 The VM creation happens in the following steps:
162
163 A series of preliminary checks are performed:
164 - We check if we're being run as root, since
165 the filesystem handling requires root priv's
166 - Each plugin's preflight_check method is called.
167 See L{VMBuilder.plugins.Plugin} documentation for details
168 - L{create_directory_structure} is called
169 - VMBuilder.disk.create_partitions is called
170 - VMBuilder.disk.create_filesystems is called
171 - .mount_partitions is called
172 - .install is called
173
174 """
175 util.checkroot()
176
177 finished = False
178 try:
179 self.preflight_check()
180 self.create_directory_structure()
181
182 disk.create_partitions(self)
183 disk.create_filesystems(self)
184 self.mount_partitions()
185
186 self.install()
187
188 self.umount_partitions()
189
190 self.hypervisor.finalize()
191
192 self.deploy()
193
194 util.fix_ownership(self.result_files)
195
196 finished = True
197 except VMBuilderException:
198 raise
199 finally:
200 if not finished:
201 logging.debug("Oh, dear, an exception occurred")
202 self.cleanup()
203
204 if not finished:
205 return(1)
206 return(0)
207
257