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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 525 - (show annotations) (download) (as text)
Thu Apr 28 03:56:08 2005 UTC (13 years, 5 months ago) by agaffney
Original Path: trunk/src/GLIArchitectureTemplate.py
File MIME type: text/x-python
File size: 42760 byte(s)
added post-install script code

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

Properties

Name Value
svn:eol-style native

  ViewVC Help
Powered by ViewVC 1.1.20