/[gli]/branches/overhaul/src/GLIArchitectureTemplate.py
Gentoo

Contents of /branches/overhaul/src/GLIArchitectureTemplate.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 571 - (show annotations) (download) (as text)
Wed May 11 17:42:14 2005 UTC (13 years, 3 months ago) by agaffney
Original Path: trunk/src/GLIArchitectureTemplate.py
File MIME type: text/x-python
File size: 44589 byte(s)
Added --nocolor to all emerge calls

1 """
2 Gentoo Linux Installer
3
4 $Id: GLIArchitectureTemplate.py,v 1.110 2005/05/11 17:42:14 agaffney Exp $
5 Copyright 2005 Gentoo Technologies Inc.
6
7 The ArchitectureTemplate is largely meant to be an abstract class and an
8 interface (yes, it is both at the same time!). The purpose of this is to create
9 subclasses that populate all the methods with working methods for that architecture.
10 The only definitions that are filled in here are architecture independent.
11
12 """
13
14 import GLIUtility, GLILogger, os, string, sys, shutil, re
15 from GLIException import *
16
17 class ArchitectureTemplate:
18 ##
19 # Initialization of the ArchitectureTemplate. Called from some other arch template.
20 # @param selfconfiguration=None A Client Configuration
21 # @param install_profile=None An Install Profile
22 # @param client_controller=None Client Controller. not same as configuration.
23 def __init__(self,configuration=None, install_profile=None, client_controller=None):
24 self._client_configuration = configuration
25 self._install_profile = install_profile
26 self._cc = client_controller
27
28 # This will get used a lot, so it's probably
29 # better to store it in a variable than to call
30 # this method 100000 times.
31 self._chroot_dir = self._client_configuration.get_root_mount_point()
32 self._logger = GLILogger.Logger(self._client_configuration.get_log_file())
33 self._compile_logfile = "/tmp/compile_output.log"
34
35 # These must be filled in by the subclass. _steps is a list of
36 # functions, that will carry out the installation. They must be
37 # in order.
38 #
39 # For example, self._steps might be: [preinstall, stage1, stage2, stage3, postinstall],
40 # where each entry is a function (with no arguments) that carries out the desired actions.
41 # Of course, steps will be different depending on the install_profile
42
43 self._architecture_name = "generic"
44 self._install_steps = [
45 (self.partition, "Partition"),
46 (self.mount_local_partitions, "Mount local partitions"),
47 (self.mount_network_shares, "Mount network (NFS) shares"),
48 (self.unpack_stage_tarball, "Unpack stage tarball"),
49 (self.configure_make_conf, "Configure /etc/make.conf"),
50 (self.prepare_chroot, "Preparing chroot"),
51 (self.install_portage_tree, "Portage tree voodoo"),
52 (self.stage1, "Performing bootstrap"),
53 (self.stage2, "Performing 'emerge system'"),
54 (self.set_root_password, "Set the root password"),
55 (self.set_timezone, "Setting timezone"),
56 (self.emerge_kernel_sources, "Emerge kernel sources"),
57 (self.build_kernel, "Building kernel"),
58 (self.install_logging_daemon, "Logger"),
59 (self.install_cron_daemon, "Cron daemon"),
60 (self.install_filesystem_tools, "Installing filesystem tools"),
61 (self.setup_network_post, "Configuring post-install networking"),
62 (self.install_bootloader, "Configuring and installing bootloader"),
63 (self.update_config_files, "Updating config files"),
64 (self.configure_rc_conf, "Updating /etc/rc.conf"),
65 (self.set_services, "Setting up services for startup"),
66 (self.set_users, "Add additional users."),
67 (self.install_packages, "Installing additional packages."),
68 (self.run_post_install_script, "Running custom post-install script"),
69 (self.finishing_cleanup, "Cleanup and unmounting local filesystems.")
70 ]
71
72
73 ##
74 # Returns the steps and their comments in an array
75 def get_install_steps(self):
76 return self._install_steps
77
78 ##
79 # Tells the frontend something
80 # @param type type of data
81 # @param data the data itself. usually a number.
82 def notify_frontend(self, type, data):
83 self._cc.addNotification(type, data)
84
85 # It is possible to override these methods in each Arch Template.
86 # It might be necessary to do so, if the arch needs something 'weird'.
87
88 ##
89 # Private function to add a /etc/init.d/ script to the given runlevel in the chroot environement
90 # @param script_name the script to be added
91 # @param runlevel="default" the runlevel to add to
92 def _add_to_runlevel(self, script_name, runlevel="default"):
93
94 status = GLIUtility.spawn("rc-update add " + script_name + " " + runlevel, display_on_tty8=True, chroot=self._chroot_dir, logfile=self._compile_logfile, append_log=True)
95 if not GLIUtility.exitsuccess(status):
96 raise GLIException("RunlevelAddError", 'fatal', '_add_to_runlevel', "Failure adding " + script_name + " to runlevel " + runlevel + "!")
97 self._logger.log("Added "+script_name+" to runlevel "+runlevel)
98
99 ##
100 # Private Function. Will return a list of packages to be emerged for a given command. Not yet used.
101 # @param cmd full command to run ('/usr/portage/scripts/bootstrap.sh --pretend' or 'emerge -p system')
102 def _get_packages_to_emerge(self, cmd):
103 return GLIUtility.spawn(cmd + r" | grep -e '\[ebuild' | sed -e 's:\[ebuild .\+ \] ::' -e 's: \[.\+\] ::' -e 's: +$::'", chroot=self._chroot_dir, return_output=True)[1].split("\n")
104
105 ##
106 # Private function. For binary installs it will attempt to quickpkg packages that are on the livecd.
107 # @param package package to be quickpkg'd.
108 def _quickpkg_deps(self, package):
109 # These need to be changed to pull values from the make.conf stuff
110 PKGDIR = "/usr/portage/packages"
111 PORTAGE_TMPDIR = "/var/tmp"
112 make_conf = self._install_profile.get_make_conf()
113 if "PKGDIR" in make_conf and make_conf['PKGDIR']: PKGDIR = make_conf['PKGDIR']
114 if "PORTAGE_TMPDIR" in make_conf and make_conf['PORTAGE_TMPDIR']: PORTAGE_TMPDIR = make_conf['PORTAGE_TMPDIR']
115 GLIUtility.spawn("mkdir -p " + self._chroot_dir + PKGDIR, logfile=self._compile_logfile, append_log=True)
116 GLIUtility.spawn("mkdir -p " + self._chroot_dir + PORTAGE_TMPDIR, logfile=self._compile_logfile, append_log=True)
117 packages = self._get_packages_to_emerge("emerge -p " + package)
118 for pkg in packages:
119 if not GLIUtility.is_file(self._chroot_dir + PKGDIR + "/All/" + pkg.split('/')[1] + ".tbz2"):
120 ret = GLIUtility.spawn("env PKGDIR='" + self._chroot_dir + PKGDIR + "' PORTAGE_TMPDIR='" + self._chroot_dir + PORTAGE_TMPDIR + "' quickpkg =" + pkg)
121 if ret:
122 # This package couldn't be quickpkg'd. This may be an error in the future
123 pass
124
125 ##
126 # Private Function. Will emerge a given package in the chroot environment.
127 # @param package package to be emerged
128 # @param binary=False defines whether to try a binary emerge (if GRP this gets ignored either way)
129 # @param binary_only=False defines whether to only allow binary emerges.
130 def _emerge(self, package, binary=False, binary_only=False):
131 #Error checking of this function is to be handled by the parent function.
132 if self._install_profile.get_grp_install():
133 self._quickpkg_deps(package)
134 return GLIUtility.spawn("emerge --nocolor -k " + package, display_on_tty8=True, chroot=self._chroot_dir, logfile=self._compile_logfile, append_log=True)
135 else:
136 if binary_only:
137 return GLIUtility.spawn("emerge --nocolor -K " + package, display_on_tty8=True, chroot=self._chroot_dir, logfile=self._compile_logfile, append_log=True)
138 elif binary:
139 return GLIUtility.spawn("emerge --nocolor -k " + package, display_on_tty8=True, chroot=self._chroot_dir, logfile=self._compile_logfile, append_log=True)
140 else:
141 return GLIUtility.spawn("emerge --nocolor " + package, display_on_tty8=True, chroot=self._chroot_dir, logfile=self._compile_logfile, append_log=True)
142
143 ##
144 # Private Function. Will edit a config file and insert a value or two overwriting the previous value
145 # (actually it only just comments out the old one)
146 # @param filename file to be edited
147 # @param newvalues a dictionary of VARIABLE:VALUE pairs
148 # @param delimeter='=' what is between the key and the value
149 # @param quotes_around_value=True whether there are quotes around the value or not (ex. "local" vs. localhost)
150 # @param only_value=False Ignore the keys and output only a value.
151 def _edit_config(self, filename, newvalues, delimeter='=', quotes_around_value=True, only_value=False):
152 if not GLIUtility.is_file(filename):
153 raise GLIException("NoSuchFileError", 'notice','_edit_config',filename + ' does not exist!')
154
155 f = open(filename)
156 file = f.readlines()
157 f.close()
158
159 for key in newvalues.keys():
160 regexpr = '^\s*#?\s*' + key + '\s*' + delimeter + '.*$'
161 regexpr = re.compile(regexpr)
162
163 for i in range(0, len(file)):
164 if regexpr.match(file[i]):
165 if not file[i][0] == '#':
166 file[i] = '#' + file[i]
167
168 file.append('\n# Added by GLI\n')
169 commentprefix = ""
170 if key == "SPACER":
171 file.append('\n')
172 elif key == "COMMENT" or key == "##comment##" or key == "##commented##":
173 file.append('# ' + newvalues[key] + '\n')
174 else:
175 if quotes_around_value:
176 newvalues[key] = '"' + newvalues[key] + '"'
177 #Only the printing of values is required.
178 if only_value:
179 file.append(newvalues[key] + '\n')
180 else:
181 file.append(key + delimeter + newvalues[key]+'\n')
182
183 f = open(filename,'w')
184 f.writelines(file)
185 f.flush()
186 f.close()
187 self._logger.log("Edited Config file "+filename)
188
189 ##
190 # Stage 1 install -- bootstraping the system
191 # If we are doing a stage 1 install, then bootstrap
192 def stage1(self):
193 if self._install_profile.get_install_stage() == 1:
194 self._logger.mark()
195 self._logger.log("Starting bootstrap.")
196 pkgs = self._get_packages_to_emerge("/usr/portage/scripts/bootstrap.sh --pretend")
197 exitstatus = GLIUtility.spawn("/usr/portage/scripts/bootstrap.sh", chroot=self._chroot_dir, display_on_tty8=True, logfile=self._compile_logfile, append_log=True)
198 if not GLIUtility.exitsuccess(exitstatus):
199 raise GLIException("Stage1Error", 'fatal','stage1', "Bootstrapping failed!")
200 self._logger.log("Bootstrap complete.")
201
202 ##
203 # Stage 2 install -- emerge -e system
204 # If we are doing a stage 1 or 2 install, then emerge system
205 def stage2(self):
206
207 if self._install_profile.get_install_stage() in [ 1, 2 ]:
208 self._logger.mark()
209 self._logger.log("Starting emerge system.")
210 pkgs = self._get_packages_to_emerge("emerge -p system") #currently quite the useless
211 exitstatus = self._emerge("--emptytree system")
212 if not GLIUtility.exitsuccess(exitstatus):
213 raise GLIException("Stage2Error", 'fatal','stage2', "Building the system failed!")
214 self._logger.log("Emerge system complete.")
215
216 ##
217 # Unpacks the stage tarball that has been specified in the profile (it better be there!)
218 def unpack_stage_tarball(self):
219 if not os.path.isdir(self._chroot_dir):
220 os.makedirs(self._chroot_dir)
221 GLIUtility.fetch_and_unpack_tarball(self._install_profile.get_stage_tarball_uri(), self._chroot_dir, temp_directory=self._chroot_dir, keep_permissions=True)
222 self._logger.log(self._install_profile.get_stage_tarball_uri()+" was unpacked.")
223
224 ##
225 # Prepares the Chroot environment by copying /etc/resolv.conf and mounting proc and dev
226 def prepare_chroot(self):
227 # Copy resolv.conf to new env
228 try:
229 shutil.copy("/etc/resolv.conf", self._chroot_dir + "/etc/resolv.conf")
230 except:
231 pass
232 ret = GLIUtility.spawn("mount -t proc none "+self._chroot_dir+"/proc")
233 if not GLIUtility.exitsuccess(ret):
234 raise GLIException("MountError", 'fatal','prepare_chroot','Could not mount /proc')
235 ret = GLIUtility.spawn("mount -o bind /dev " + self._chroot_dir + "/dev")
236 if not GLIUtility.exitsuccess(ret):
237 raise GLIException("MountError", 'fatal','prepare_chroot','Could not mount /dev')
238 GLIUtility.spawn("mv " + self._compile_logfile + " " + self._chroot_dir + self._compile_logfile + " && ln -s " + self._chroot_dir + self._compile_logfile + " " + self._compile_logfile)
239 self._logger.log("Chroot environment ready.")
240
241 ##
242 # Installs a list of packages specified in the profile. Will install any extra software!
243 # In the future this function will lead to better things. It may even wipe your ass for you.
244 def install_packages(self):
245 installpackages = self._install_profile.get_install_packages()
246 for package in installpackages:
247 self._logger.log("Starting emerge " + package)
248 status = self._emerge(package)
249 if not GLIUtility.exitsuccess(status):
250 self._logger.log("Could not emerge " + package + "!")
251 # raise GLIException("InstallPackagesError", 'warning', 'install_packages', "Could not emerge " + package + "!")
252 else:
253 self._logger.log("Emerged package: " + package)
254
255 ##
256 # Will set the list of services to runlevel default. This is a temporary solution!
257 def set_services(self):
258 services = self._install_profile.get_services()
259 for service in services:
260 status = self._add_to_runlevel(service)
261
262 ##
263 # Will grab partition info from the profile and mount all partitions with a specified mountpoint (and swap too)
264 def mount_local_partitions(self):
265 #{ 1: { 'end': 1999871, 'format': False, 'mb': 0,
266 #'mountopts': '', 'mountpoint': '', 'start': 63, 'type': 'linux-swap'},
267 #2: { 'end': 240121727, 'format': False, 'mb': 0, 'mountopts': '',
268 #'mountpoint': '', 'start': 1999872, 'type': 'ext3'}}
269
270 parts = self._install_profile.get_partition_tables()
271 parts_to_mount = {}
272 for device in parts:
273 #in parts['/dev/hda']
274 for partition in parts[device]:
275 #print parts[device][partition]
276 mountpoint = parts[device][partition]['mountpoint']
277 mountopts = parts[device][partition]['mountopts']
278 minor = str(int(parts[device][partition]['minor']))
279 partition_type = parts[device][partition]['type']
280 if mountpoint:
281 if mountopts:
282 mountopts = "-o "+mountopts+" "
283 if partition_type:
284 partition_type = "-t "+partition_type+" "
285 parts_to_mount[mountpoint]= {0: mountopts, 1: partition_type, 2: minor}
286
287 if partition_type == "linux-swap":
288 ret = GLIUtility.spawn("swapon "+device+minor)
289 if not GLIUtility.exitsuccess(ret):
290 self._logger.log("ERROR! : Could not activate swap!")
291 # raise GLIException("MountError", 'warning','mount_local_partitions','Could not activate swap')
292 sorted_list = []
293 for key in parts_to_mount.keys(): sorted_list.append(key)
294 sorted_list.sort()
295
296 for mountpoint in sorted_list:
297 mountopts = parts_to_mount[mountpoint][0]
298 partition_type = parts_to_mount[mountpoint][1]
299 minor = parts_to_mount[mountpoint][2]
300 if not GLIUtility.is_file(self._chroot_dir+mountpoint):
301 exitstatus = GLIUtility.spawn("mkdir -p " + self._chroot_dir + mountpoint)
302 if exitstatus != 0:
303 raise GLIException("MkdirError", 'fatal','mount_local_partitions', "Making the mount point failed!")
304 ret = GLIUtility.spawn("mount "+partition_type+mountopts+device+minor+" "+self._chroot_dir+mountpoint, display_on_tty8=True, logfile=self._compile_logfile, append_log=True)
305 if not GLIUtility.exitsuccess(ret):
306 raise GLIException("MountError", 'fatal','mount_local_partitions','Could not mount a partition')
307 self._logger.log("Mounted mountpoint:"+mountpoint)
308 ##
309 # Mounts all network shares to the local machine
310 def mount_network_shares(self):
311 """
312 <agaffney> it'll be much easier than mount_local_partitions
313 <agaffney> make sure /etc/init.d/portmap is started
314 <agaffney> then mount each one: mount -t nfs -o <mountopts> <host>:<export> <mountpoint>
315 """
316 nfsmounts = self._install_profile.get_network_mounts()
317 for netmount in nfsmounts:
318 if netmount['type'] == "NFS" or netmount['type'] == "nfs":
319 mountopts = netmount['mountopts']
320 if mountopts:
321 mountopts = "-o "+mountopts
322 host = netmount['host']
323 export = netmount['export']
324 mountpoint = netmount['mountpoint']
325 if not GLIUtility.is_file(self._chroot_dir+mountpoint):
326 exitstatus = GLIUtility.spawn("mkdir -p " + self._chroot_dir + mountpoint)
327 if exitstatus != 0:
328 raise GLIException("MkdirError", 'fatal','mount_network_shares', "Making the mount point failed!")
329 ret = GLIUtility.spawn("mount -t nfs "+mountopts+" "+host+":"+export+" "+self._chroot_dir+mountpoint, display_on_tty8=True, logfile=self._compile_logfile, append_log=True)
330 if not GLIUtility.exitsuccess(ret):
331 raise GLIException("MountError", 'fatal','mount_network_shares','Could not mount an NFS partition')
332 self._logger.log("Mounted netmount at mountpoint:"+mountpoint)
333
334 ##
335 # Gets sources from CD (required for non-network installation)
336 # WARNING: There will no longer be sources on the future livecds. this will have to change!
337 def fetch_sources_from_cd(self):
338 """
339 THIS FUNCTION IS NO LONGER VALID
340 if not GLIUtility.is_file(self._chroot_dir+"/usr/portage/distfiles"):
341 exitstatus = GLIUtility.spawn("mkdir -p /usr/portage/distfiles",chroot=self._chroot_dir)
342 if exitstatus != 0:
343 raise GLIException("MkdirError", 'fatal','install_portage_tree',"Making the distfiles directory failed.")
344 exitstatus = GLIUtility.spawn("cp /mnt/cdrom/distfiles/* "+self._chroot_dir+"/usr/portage/distfiles/", display_on_tty8=True, logfile=self._compile_logfile, append_log=True)
345 if exitstatus != 0:
346 raise GLIException("PortageError", 'fatal','install_portage_tree',"Failed to copy the distfiles to the new system")
347 """
348 self._logger.log("Distfiles copied from cd. NOT!")
349
350 ##
351 # Gets grp binary packages from CD (required for non-network binary installation)
352 # This will not work anymore at all. I don't know why it's even still here.
353 def fetch_grp_from_cd(self):
354 pass
355
356 ##
357 # Configures the new /etc/make.conf
358 def configure_make_conf(self):
359 # Get make.conf options
360 options = self._install_profile.get_make_conf()
361
362 # For each configuration option...
363 for key in options.keys():
364
365 # Add/Edit it into make.conf
366 self._edit_config(self._chroot_dir + "/etc/make.conf", {key: options[key]})
367 self._logger.log("Make.conf configured")
368
369 ##
370 # This will get/update the portage tree. If you want to snapshot or mount /usr/portage use "custom".
371 def install_portage_tree(self):
372 # Check the type of portage tree fetching we'll do
373 # If it is custom, follow the path to the custom tarball and unpack it
374
375 # This is a hack to copy the LiveCD's rsync into the chroot since it has the sigmask patch
376 GLIUtility.spawn("cp -a /usr/bin/rsync " + self._chroot_dir + "/usr/bin/rsync")
377 GLIUtility.spawn("cp -a /usr/lib/libpopt* " + self._chroot_dir + "/usr/lib")
378
379 if self._install_profile.get_portage_tree_sync_type() == "snapshot" or self._install_profile.get_portage_tree_sync_type() == "custom": # Until this is finalized
380
381 # Get portage tree info
382 portage_tree_snapshot_uri = self._install_profile.get_portage_tree_snapshot_uri()
383 if portage_tree_snapshot_uri:
384 # Fetch and unpack the tarball
385 GLIUtility.fetch_and_unpack_tarball(portage_tree_snapshot_uri, self._chroot_dir + "/usr/", self._chroot_dir + "/")
386 self._logger.log("Portage tree install was custom.")
387 # If the type is webrsync, then run emerge-webrsync
388 elif self._install_profile.get_portage_tree_sync_type() == "webrsync":
389 exitstatus = GLIUtility.spawn("emerge-webrsync", chroot=self._chroot_dir, display_on_tty8=True, logfile=self._compile_logfile, append_log=True)
390 if exitstatus != 0:
391 raise GLIException("EmergeWebRsyncError", 'fatal','install_portage_tre', "Failed to retrieve portage tree!")
392 self._logger.log("Portage tree sync'd using webrsync")
393 # Otherwise, just run emerge sync
394 else:
395 exitstatus = self._emerge("sync")
396 if exitstatus != 0:
397 raise GLIException("EmergeSyncError", 'fatal','install_portage_tree', "Failed to retrieve portage tree!")
398 self._logger.log("Portage tree sync'd")
399
400 ##
401 # Sets the timezone for the new environment
402 def set_timezone(self):
403
404 # Set symlink
405 if os.access(self._chroot_dir + "/etc/localtime", os.W_OK):
406 GLIUtility.spawn("rm "+self._chroot_dir + "/etc/localtime")
407 GLIUtility.spawn("ln -s ../usr/share/zoneinfo/" + self._install_profile.get_time_zone() + " /etc/localtime", chroot=self._chroot_dir)
408 if not (self._install_profile.get_time_zone() == "UTC"):
409 self._edit_config(self._chroot_dir + "/etc/rc.conf", {"CLOCK":"local"})
410 self._logger.log("Timezone set.")
411
412 ##
413 # Configures /etc/fstab on the new envorinment
414 def configure_fstab(self):
415 newfstab = ""
416 parts = self._install_profile.get_partition_tables()
417 for device in parts:
418 #in parts['/dev/hda']
419 for partition in parts[device]:
420 #print parts[device][partition]
421 mountpoint = parts[device][partition]['mountpoint']
422 minor = str(int(parts[device][partition]['minor']))
423 partition_type = parts[device][partition]['type']
424 mountopts = parts[device][partition]['mountopts']
425 if not mountopts.strip(): mountopts = "defaults"
426 if mountpoint:
427 if not GLIUtility.is_file(self._chroot_dir+mountpoint):
428 exitstatus = GLIUtility.spawn("mkdir -p " + self._chroot_dir + mountpoint)
429 if exitstatus != 0:
430 raise GLIException("MkdirError", 'fatal','configure_fstab', "Making the mount point failed!")
431 newfstab += device+minor+"\t "+mountpoint+"\t "+partition_type+"\t "+mountopts+"\t\t "
432 if mountpoint == "/boot":
433 newfstab += "1 2\n"
434 elif mountpoint == "/":
435 newfstab += "0 1\n"
436 else:
437 newfstab += "0 0\n"
438 if partition_type == "linux-swap":
439 newfstab += device+minor+"\t none swap sw 0 0\n"
440 newfstab += "none /proc proc defaults 0 0\n"
441 newfstab += "none /dev/shm tmpfs defaults 0 0\n"
442 if GLIUtility.is_device("/dev/cdroms/cdrom0"):
443 newfstab += "/dev/cdroms/cdrom0 /mnt/cdrom auto noauto,user 0 0\n"
444
445 for netmount in self._install_profile.get_network_mounts():
446 if netmount['type'] == "nfs":
447 newfstab += netmount['host'] + ":" + netmount['export'] + "\t" + netmount['mountpoint'] + "\tnfs\t" + netmount['mountopts'] + "\t0 0\n"
448
449 file_name = self._chroot_dir + "/etc/fstab"
450 try:
451 shutil.move(file_name, file_name + ".OLDdefault")
452 except:
453 pass
454 f = open(file_name, 'w')
455 f.writelines(newfstab)
456 f.close()
457 self._logger.log("fstab configured.")
458
459 ##
460 # Fetches desired kernel sources, unless you're using a livecd-kernel in which case it does freaky stuff.
461 def emerge_kernel_sources(self):
462 self._logger.log("Starting emerge_kernel")
463 kernel_pkg = self._install_profile.get_kernel_source_pkg()
464 # if kernel_pkg:
465 if kernel_pkg == "livecd-kernel":
466 PKGDIR = "/usr/portage/packages"
467 PORTAGE_TMPDIR = "/var/tmp"
468 make_conf = self._install_profile.get_make_conf()
469 if "PKGDIR" in make_conf: PKGDIR = make_conf['PKGDIR']
470 if "PORTAGE_TMPDIR" in make_conf: PORTAGE_TMPDIR = make_conf['PORTAGE_TMPDIR']
471 GLIUtility.spawn("mkdir -p " + self._chroot_dir + PKGDIR, logfile=self._compile_logfile, append_log=True)
472 GLIUtility.spawn("mkdir -p " + self._chroot_dir + PORTAGE_TMPDIR, logfile=self._compile_logfile, append_log=True)
473 ret = GLIUtility.spawn("env PKGDIR=" + self._chroot_dir + PKGDIR + " PORTAGE_TMPDIR=" + self._chroot_dir + PORTAGE_TMPDIR + " quickpkg livecd-kernel")
474 ret = GLIUtility.spawn("env PKGDIR=" + PKGDIR + " emerge -K sys-kernel/livecd-kernel", chroot=self._chroot_dir)
475
476 #these are the hotplug/coldplug steps from build_kernel copied over here. they will NOT be run there.
477 exitstatus = self._emerge("hotplug")
478 if exitstatus != 0:
479 raise GLIException("EmergeHotplugError", 'fatal','build_kernel', "Could not emerge hotplug!")
480 self._logger.log("Hotplug emerged.")
481 exitstatus = self._emerge("coldplug")
482 if exitstatus != 0:
483 raise GLIException("EmergeColdplugError", 'fatal','build_kernel', "Could not emerge coldplug!")
484 self._logger.log("Coldplug emerged. Now they should be added to the default runlevel.")
485
486 self._add_to_runlevel("hotplug")
487 self._add_to_runlevel("coldplug", runlevel="boot")
488 else:
489 exitstatus = self._emerge(kernel_pkg)
490 if exitstatus != 0:
491 raise GLIException("EmergeKernelSourcesError", 'fatal','emerge_kernel_sources',"Could not retrieve kernel sources!")
492 try:
493 os.stat(self._chroot_dir + "/usr/src/linux")
494 except:
495 kernels = os.listdir(self._chroot_dir+"/usr/src")
496 found_a_kernel = False
497 counter = 0
498 while not found_a_kernel:
499 if kernels[counter][0:6]=="linux-":
500 exitstatus = GLIUtility.spawn("ln -s /usr/src/"+kernels[counter]+ " /usr/src/linux",chroot=self._chroot_dir)
501 if exitstatus != 0:
502 raise GLIException("EmergeKernelSourcesError", 'fatal','emerge_kernel_sources',"Could not make a /usr/src/linux symlink")
503 found_a_kernel = True
504 else:
505 counter = counter + 1
506 self._logger.log("Kernel sources:"+kernel_pkg+" emerged and /usr/src/linux symlinked.")
507
508 ##
509 # Builds the kernel using genkernel or regularly if given a custom .config file in the profile
510 def build_kernel(self):
511 self._logger.mark()
512 self._logger.log("Starting build_kernel")
513 # No building necessary if using the LiveCD's kernel/initrd
514 if self._install_profile.get_kernel_source_pkg() == "livecd-kernel": return
515 # Get the uri to the kernel config
516 kernel_config_uri = self._install_profile.get_kernel_config_uri()
517 if kernel_config_uri == "": #use genkernel if no specific config
518
519 exitstatus = self._emerge("genkernel")
520 if exitstatus != 0:
521 raise GLIException("EmergeGenKernelError", 'fatal','build_kernel', "Could not emerge genkernel!")
522 self._logger.log("Genkernel emerged. Beginning kernel compile.")
523 # Null the genkernel_options
524 genkernel_options = ""
525
526 # If the uri for the kernel config is not null, then
527 if kernel_config_uri != "":
528 GLIUtility.get_uri(kernel_config_uri, self._chroot_dir + "/root/kernel_config")
529 genkernel_options = genkernel_options + " --kernel-config=/root/kernel_config"
530
531 # Decide whether to use bootsplash or not
532 if self._install_profile.get_kernel_bootsplash():
533 genkernel_options = genkernel_options + " --bootsplash"
534 else:
535 genkernel_options = genkernel_options + " --no-bootsplash"
536 # Run genkernel in chroot
537 #print "genkernel all " + genkernel_options
538 exitstatus = GLIUtility.spawn("genkernel all " + genkernel_options, chroot=self._chroot_dir, display_on_tty8=True, logfile=self._compile_logfile, append_log=True)
539 if exitstatus != 0:
540 raise GLIException("KernelBuildError", 'fatal', 'build_kernel', "Could not build kernel!")
541
542 exitstatus = self._emerge("hotplug")
543 if exitstatus != 0:
544 raise GLIException("EmergeHotplugError", 'fatal','build_kernel', "Could not emerge hotplug!")
545 self._logger.log("Hotplug emerged.")
546 exitstatus = self._emerge("coldplug")
547 if exitstatus != 0:
548 raise GLIException("EmergeColdplugError", 'fatal','build_kernel', "Could not emerge coldplug!")
549 self._logger.log("Coldplug emerged. Now they should be added to the default runlevel.")
550
551 self._add_to_runlevel("hotplug")
552 self._add_to_runlevel("coldplug", runlevel="boot")
553 self._logger.log("Genkernel complete.")
554 else: #CUSTOM CONFIG
555 #Copy the kernel .config to the proper location in /usr/src/linux
556 try:
557 GLIUtility.get_uri(kernel_config_uri, self._chroot_dir + "/root/kernel_config")
558 except:
559 raise GLIException("KernelBuildError", 'fatal', 'build_kernel', "Could not copy kernel config!")
560
561 kernel_compile_script = "#!/bin/bash\n"
562 kernel_compile_script += "cp /root/kernel_config /usr/src/linux/.config\n"
563 kernel_compile_script += "cd /usr/src/linux\n"
564 kernel_compile_script += "make \nmake modules_install \n"
565
566 #Ok now that it's built, copy it to /boot/kernel-* for bootloader code to find it
567 if self._client_configuration.get_architecture_template() == "x86":
568 kernel_compile_script += "cp /usr/src/linux/arch/i386/boot/bzImage /boot/kernel-custom\n"
569 f = open(self._chroot_dir+"/root/kernel_script", 'w')
570 f.writelines(kernel_compile_script)
571 f.close()
572 #Build the kernel
573 exitstatus1 = GLIUtility.spawn("chmod u+x "+self._chroot_dir+"/root/kernel_script")
574 exitstatus2 = GLIUtility.spawn("/root/kernel_script", chroot=self._chroot_dir, display_on_tty8=True, logfile=self._compile_logfile, append_log=True)
575 if (exitstatus1 != 0) or (exitstatus2 != 0):
576 raise GLIException("KernelBuildError", 'fatal', 'build_kernel', "Could not build custom kernel!")
577
578 #i'm sure i'm forgetting something here.
579 #cleanup
580 exitstatus = GLIUtility.spawn("rm "+self._chroot_dir+"/root/kernel_script")
581 #it's not important if this fails.
582 self._logger.log("Custom kernel complete")
583
584 ##
585 # Installs and sets up logging daemon on the new system. adds to runlevel too.
586 def install_logging_daemon(self):
587
588 # Get loggin daemon info
589 logging_daemon_pkg = self._install_profile.get_logging_daemon_pkg()
590 if logging_daemon_pkg:
591 # Emerge Logging Daemon
592 exitstatus = self._emerge(logging_daemon_pkg)
593 if exitstatus != 0:
594 raise GLIException("LoggingDaemonError", 'fatal','install_logging_daemon', "Could not emerge " + logging_daemon_pkg + "!")
595
596 # Add Logging Daemon to default runlevel
597 self._add_to_runlevel(logging_daemon_pkg)
598 self._logger.log("Logging daemon installed: "+logging_daemon_pkg)
599 ##
600 # Installs and sets up cron package.
601 def install_cron_daemon(self):
602
603 # Get cron daemon info
604 cron_daemon_pkg = self._install_profile.get_cron_daemon_pkg()
605 if cron_daemon_pkg:
606 # Emerge Cron Daemon
607 exitstatus = self._emerge(cron_daemon_pkg)
608 if exitstatus != 0:
609 raise GLIException("CronDaemonError", 'fatal', 'install_cron_daemon', "Could not emerge " + cron_daemon_pkg + "!")
610
611 # Add Cron Daemon to default runlevel
612 self._add_to_runlevel(cron_daemon_pkg)
613
614 # If the Cron Daemon is not vixie-cron, run crontab
615 if cron_daemon_pkg != "vixie-cron":
616 exitstatus = GLIUtility.spawn("crontab /etc/crontab", chroot=self._chroot_dir, display_on_tty8=True)
617 if exitstatus != 0:
618 raise GLIException("CronDaemonError", 'fatal', 'install_cron_daemon', "Failure making crontab!")
619 self._logger.log("Cron daemon installed and configured: "+cron_daemon_pkg)
620 ##
621 # This will parse the partitions looking for types that require fstools and emerge them if found.
622 def install_filesystem_tools(self):
623 "Installs and sets up fstools"
624 # Get the list of file system tools to be installed
625 parts = self._install_profile.get_partition_tables()
626 filesystem_tools = []
627 for device in parts:
628 #in parts['/dev/hda']
629 for partition in parts[device]:
630 #print parts[device][partition]
631 partition_type = parts[device][partition]['type']
632 if partition_type not in filesystem_tools:
633 filesystem_tools.append(partition_type)
634 for filesystem in filesystem_tools:
635 if filesystem.lower() == "xfs":
636 exitstatus = self._emerge("xfsprogs")
637 if exitstatus != 0:
638 self._logger.log("ERROR! : Could not emerge xfsprogs!")
639 else:
640 self._logger.log("FileSystemTool xfsprogs was emerged successfully.")
641 if filesystem.lower() == "reiserfs":
642 exitstatus = self._emerge("reiserfsprogs")
643 if exitstatus != 0:
644 self._logger.log("ERROR! : Could not emerge reiserfsprogs!")
645 else:
646 self._logger.log("FileSystemTool reiserfsprogs was emerged successfully.")
647 if filesystem.lower() == "jfs":
648 exitstatus = self._emerge("jfsutils")
649 if exitstatus != 0:
650 self._logger.log("ERROR! : Could not emerge jfsutils!")
651 else:
652 self._logger.log("FileSystemTool jfsutils was emerged successfully.")
653
654 ##
655 # Installs rp-pppoe but does not configure it. This function is quite the unknown.
656 def install_rp_pppoe(self):
657
658 # If user wants us to install rp-pppoe, then do so
659 if self._install_profile.get_install_rp_pppoe():
660 exitstatus = self._emerge("rp-pppoe")
661 if exitstatus != 0:
662 self._logger.log("ERROR! : Could not emerge rp-pppoe!")
663 # raise GLIException("RP_PPPOEError", 'warning', 'install_rp_pppoe', "Could not emerge rp-pppoe!")
664 else:
665 self._logger.log("rp-pppoe emerged but not set up.")
666 # Should we add a section here to automatically configure rp-pppoe?
667 # I think it should go into the setup_network_post section
668 # What do you guys think? <-- said by unknown. samyron or npmcallum
669
670 ##
671 # Installs and sets up pcmcia-cs if selected in the profile
672 def install_pcmcia_cs(self):
673 # If user wants us to install pcmcia-cs, then do so
674 if self._install_profile.get_install_pcmcia_cs():
675 exitstatus = self._emerge("pcmcia-cs")
676 if exitstatus != 0:
677 self._logger.log("ERROR! : Could not emerge pcmcia-cs!")
678 # raise GLIException("PCMCIA_CSError", 'warning', 'install_pcmcia_cs', "Could not emerge pcmcia-cs!")
679
680 # Add pcmcia-cs to the default runlevel
681 else:
682 self._add_to_runlevel(pcmcia)
683 self._logger.log("PCMCIA_CS emerged and configured.")
684
685 ##
686 # This runs etc-update and then re-overwrites the files by running the configure_*'s to keep our values.
687 def update_config_files(self):
688 "Runs etc-update (overwriting all config files), then re-configures the modified ones"
689 # Run etc-update overwriting all config files
690 status = GLIUtility.spawn('echo "-5" | chroot '+self._chroot_dir+' etc-update', display_on_tty8=True)
691 if not GLIUtility.exitsuccess(status):
692 self._logger.log("ERROR! : Could not update the config files!")
693 # raise GLIException("EtcUpdateError", 'warning', 'update_config_files', "Could not update config files!")
694 else:
695 self.configure_make_conf()
696 self.configure_fstab()
697 self.configure_rc_conf()
698 self._logger.log("Config files updated using etc-update. make.conf/fstab/rc.conf restored.")
699
700 ##
701 # Configures /etc/rc.conf
702 def configure_rc_conf(self):
703
704 # Get make.conf options
705 options = self._install_profile.get_rc_conf()
706
707 # For each configuration option...
708 for key in options.keys():
709
710 # Add/Edit it into rc.conf
711 self._edit_config(self._chroot_dir + "/etc/rc.conf", {key: options[key]})
712 self._logger.log("rc.conf configured.")
713
714 ##
715 # Sets up the network for the first boot
716 def setup_network_post(self):
717
718 # Get hostname, domainname and nisdomainname
719 hostname = self._install_profile.get_hostname()
720 domainname = self._install_profile.get_domainname()
721 nisdomainname = self._install_profile.get_nisdomainname()
722
723 # Write the hostname to the hostname file
724 open(self._chroot_dir + "/etc/hostname", "w").write(hostname + "\n")
725
726 # Write the domainname to the nisdomainname file
727 if domainname:
728 open(self._chroot_dir + "/etc/dnsdomainname", "w").write(domainname + "\n")
729 self._add_to_runlevel("domainname")
730
731 # Write the nisdomainname to the nisdomainname file
732 if nisdomainname:
733 open(self._chroot_dir + "/etc/nisdomainname", "w").write(nisdomainname + "\n")
734 self._add_to_runlevel("domainname")
735
736 #
737 # EDIT THE /ETC/HOSTS FILE
738 #
739
740 # The address we are editing is 127.0.0.1
741 hosts_ip = "127.0.0.1"
742
743 # If the hostname is localhost
744 if hostname == "localhost":
745 # If a domainname is set
746 if domainname:
747 hosts_line = hostname + "." + domainname + "\t" + hostname
748 else:
749 hosts_line = hostname
750 # If the hostname is not localhost
751 else:
752 # If a domainname is set
753 if domainname:
754 hosts_line = hostname + "." + domainname + "\t" + hostname + "\tlocalhost"
755 else:
756 hosts_line = "localhost\t" + hostname
757
758 # Write to file
759 self._edit_config(self._chroot_dir + "/etc/hosts", {hosts_ip: hosts_line}, delimeter='\t', quotes_around_value=False)
760
761 #
762 # SET DEFAULT GATEWAY
763 #
764
765 # Get default gateway
766 default_gateway = self._install_profile.get_default_gateway()
767
768 # If the default gateway exists, add it
769 if default_gateway:
770 default_gateway_string = default_gateway[0] + "/" + default_gateway[1]
771 self._edit_config(self._chroot_dir + "/etc/conf.d/net", {"gateway": default_gateway_string})
772
773 #
774 # SET RESOLV INFO
775 #
776
777 # Get dns servers
778 dns_servers = self._install_profile.get_dns_servers()
779
780 # Clear the list
781 resolv_output = []
782
783 # If dns servers are set
784 if dns_servers:
785
786
787 # Parse each dns server
788 for dns_server in dns_servers:
789 # Add the server to the output
790 resolv_output.append("nameserver " + dns_server +"\n")
791
792 # If the domainname is set, then also output it
793 if domainname:
794 resolv_output.append("search " + domainname + "\n")
795
796 # Output to file
797 resolve_conf = open(self._chroot_dir + "/etc/resolv.conf", "w")
798 resolve_conf.writelines(resolv_output)
799 resolve_conf.close()
800
801 #
802 # PARSE INTERFACES
803 #
804
805 # Fetch interfaces
806 interfaces = self._install_profile.get_network_interfaces()
807 emerge_dhcp = False
808 # Parse each interface
809 for interface in interfaces.keys():
810
811 # Set what kind of interface it is
812 interface_type = interface[:3]
813
814 # Check to see if there is a startup script for this interface, if there isn't link to the proper script
815 try:
816 os.stat(self._chroot_dir + "/etc/init.d/net." + interface)
817 except:
818 os.symlink(self._chroot_dir + "/etc/init.d/net." + interface_type + "0", self._chroot_dir + "/etc/init.d/net." + interface)
819
820 # If we are going to load the network at boot...
821 #if interfaces[interface][2]: #THIS FEATURE NO LONGER EXISTS
822
823 # Add it to the default runlevel
824 self._add_to_runlevel("net."+interface) # moved a bit <-- for indentation
825
826 #
827 # ETHERNET
828 #
829 if interface_type == "eth":
830
831 #
832 # STATIC IP
833 #
834 # If the post-install device info is not None, then it is a static ip addy
835 if interfaces[interface][1]:
836 ip = interfaces[interface][0]
837 broadcast = interfaces[interface][1]
838 netmask = interfaces[interface][2]
839 # aliases = interfaces[interface][1][3]
840 # alias_ips = []
841 # alias_broadcasts = []
842 # alias_netmasks = []
843
844 # Write the static ip config to /etc/conf.d/net
845 self._edit_config(self._chroot_dir + "/etc/conf.d/net", {"iface_" + interface: ip + " broadcast " + broadcast + " netmask " + netmask})
846
847 # If aliases are set
848 # if aliases:
849
850 # Parse aliases to format alias info
851 # for alias in aliases:
852 # alias_ips.append(alias[0])
853 # alias_broadcasts.append(alias[1])
854 # alias_netmasks.append(allias[2])
855
856 # Once the alias info has been gathered, then write it out
857 # Alias ips first
858 # self._edit_config(self._chroot_dir + "/etc/conf.d/net", "alias_" + interface, string.join(alias_ips))
859 # Alias broadcasts next
860 # self._edit_config(self._chroot_dir + "/etc/conf.d/net", "broadcast_" + interface, string.join(alias_broadcasts))
861 # Alias netmasks last
862 # self._edit_config(self._chroot_dir + "/etc/conf.d/net", "netmask_" + interface, string.join(alias_netmasks))
863
864 #
865 # DHCP IP
866 #
867 else:
868 self._edit_config(self._chroot_dir + "/etc/conf.d/net", {"iface_" + interface: "dhcp"})
869 emerge_dhcp = True
870 if emerge_dhcp:
871 exitstatus = self._emerge("dhcpcd")
872 if exitstatus != 0:
873 self._logger.log("ERROR! : Could not emerge dhcpcd!")
874 else:
875 self._logger.log("dhcpcd emerged.")
876
877 ##
878 # Sets the root password
879 def set_root_password(self):
880 status = GLIUtility.spawn('echo \'root:' + self._install_profile.get_root_pass_hash() + '\' | chroot '+self._chroot_dir+' chpasswd -e')
881 if not GLIUtility.exitsuccess(status):
882 raise GLIException("SetRootPasswordError", 'fatal', 'set_root_password', "Failure to set root password!")
883 self._logger.log("Root Password set on the new system.")
884
885 ##
886 # Sets up the new users for the system
887 def set_users(self):
888 # Loop for each user
889 for user in self._install_profile.get_users():
890
891 # Get values from the tuple
892 username = user[0]
893 password_hash = user[1]
894 groups = user[2]
895 shell = user[3]
896 home_dir = user[4]
897 uid = user[5]
898 comment = user[6]
899
900 options = [ "-m", "-p '" + password_hash + "'" ]
901
902 # If the groups are specified
903 if groups:
904
905 # If just one group is listed as a string, make it a list
906 if groups == str:
907 groups = [ groups ]
908
909 # If only 1 group is listed
910 if len(groups) == 1:
911 options.append("-G " + groups[0])
912
913 # If there is more than one group
914 elif len(groups) > 1:
915 options.append('-G "' + string.join(groups, ",") + '"')
916
917 # Attempt to add the group (will return success when group exists)
918 for group in groups:
919 # Add the user
920 exitstatus = GLIUtility.spawn('groupadd -f ' + group, chroot=self._chroot_dir, logfile=self._compile_logfile, append_log=True, display_on_tty8=True)
921 if not GLIUtility.exitsuccess(exitstatus):
922 self._logger.log("ERROR! : Failure to add group " + group+" and it wasn't that the group already exists!")
923
924
925 # If a shell is specified
926 if shell:
927 options.append("-s " + shell)
928
929 # If a home dir is specified
930 if home_dir:
931 options.append("-d " + home_dir)
932
933 # If a UID is specified
934 if uid:
935 options.append("-u " + str(uid))
936
937 # If a comment is specified
938 if comment:
939 options.append('-c "' + comment + '"')
940
941 # Add the user
942 exitstatus = GLIUtility.spawn('useradd ' + string.join(options) + ' ' + username, chroot=self._chroot_dir, logfile=self._compile_logfile, append_log=True, display_on_tty8=True)
943 if not GLIUtility.exitsuccess(exitstatus):
944 self._logger.log("ERROR! : Failure to add user " + username)
945 # raise GLIException("AddUserError", 'warning', 'set_users', "Failure to add user " + username)
946 else:
947 self._logger.log("User "+username+"was added.")
948
949 ##
950 # This function will handle the various cleanup tasks as well as unmounting the filesystems for reboot.
951 def finishing_cleanup(self):
952 #These are temporary until I come up with a nicer idea.
953 #get rid of the compile_output file so the symlink doesn't get screwed up.
954
955 #we copy the log over to the new system.
956 install_logfile = self._client_configuration.get_log_file()
957 try:
958 shutil.copy(install_logfile, self._chroot_dir + install_logfile)
959 except:
960 pass
961 #Now we're done logging as far as the new system is concerned.
962
963 #Unmount the /proc and /dev that we mounted in prepare_chroot
964 #There really isn't a reason to log errors here.
965 ret = GLIUtility.spawn("umount "+self._chroot_dir+"/proc", display_on_tty8=True, logfile=self._compile_logfile, append_log=True)
966 ret = GLIUtility.spawn("umount "+self._chroot_dir+"/dev", display_on_tty8=True, logfile=self._compile_logfile, append_log=True)
967 #temp hack to unmount the new root.
968 ret = GLIUtility.spawn("umount "+self._chroot_dir, display_on_tty8=True, logfile=self._compile_logfile, append_log=True)
969 #insert code here to unmount the swap partition, if there is one.
970
971 GLIUtility.spawn("rm /tmp/compile_output.log && rm " + install_logfile)
972
973 ##
974 # This is a stub function to be done by the individual arch. I don't think it's even needed here.
975 # but it's nice having it just incase.
976 def install_bootloader(self):
977 "THIS FUNCTION MUST BE DONE BY THE INDIVIDUAL ARCH"
978 pass
979
980 def run_post_install_script(self):
981 if self._install_profile.get_post_install_script_uri():
982 try:
983 GLIUtility.get_uri(self._install_profile.get_post_install_script_uri(), self._chroot_dir + "/tmp/post-install")
984 GLIUtility.spawn("chmod a+x /tmp/post-install && /tmp/post-install", chroot=self._chroot_dir, display_on_tty8=True, logfile=self._compile_logfile, append_log=True)
985 except:
986 raise GLIException("RunPostInstallScriptError", 'fatal', 'run_post_install_script', "Failed to retrieve and/or execute post-install script")
987
988 # FIXME: UNKNOWN PURPOSE
989 #
990 ##
991 def set_etc_portage(self):
992 etc_portage = self._install_profile.get_etc_portage()
993
994 # Loop through the required files.
995 for file in etc_portage:
996 contents = enumerate(etc_portage[file])
997 self._logger.log("Configuring /etc/portage/" + file)
998 self._edit_config(self._chroot_dir + "/etc/portage/" + file, {"COMMENT": "GLI additions ===>"})
999
1000 # Set up the contents hash to pass to the config writer.
1001 contents = {}
1002 for key,value in enumerate(etc_portage[file]):
1003 contents[str(key)] = string.strip(value)
1004
1005 # Write out the contents in one go.
1006 self._edit_config(self._chroot_dir + "/etc/portage/" + file, contents, "", False, True)
1007
1008 self._edit_config(self._chroot_dir + "/etc/make.conf", {"COMMENT": "<=== End GLI additions"})
1009 self._logger.log("Finished configuring /etc/portage/" + file)

Properties

Name Value
svn:eol-style native

  ViewVC Help
Powered by ViewVC 1.1.20