/[gli]/trunk/src/GLIInstallProfile.py
Gentoo

Contents of /trunk/src/GLIInstallProfile.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 457 - (show annotations) (download) (as text)
Wed Mar 30 00:10:50 2005 UTC (15 years, 8 months ago) by agaffney
File MIME type: text/x-python
File size: 40449 byte(s)
Patch from zahna for extra arguments to the kernel.

1 """
2 Gentoo Linux Installer
3
4 $Id: GLIInstallProfile.py,v 1.37 2005/03/30 00:10:50 agaffney Exp $
5 Copyright 2004 Gentoo Technologies Inc.
6
7 The GLI module contains all classes used in the Gentoo Linux Installer (or GLI).
8 """
9
10 import string
11 import xml.sax
12 import os
13 import GLIUtility
14 import SimpleXMLParser
15 from GLIException import *
16
17 class InstallProfile:
18 """
19 An object representation of a profile.
20
21 InstallProfile is an object representation of a parsed installation
22 profile file.
23 """
24
25 def __init__(self):
26 parser = SimpleXMLParser.SimpleXMLParser()
27
28 parser.addHandler('gli-profile/stage-tarball', self.set_stage_tarball_uri)
29 parser.addHandler('gli-profile/kernel-initrd', self.set_kernel_initrd)
30 parser.addHandler('gli-profile/kernel-args', self.set_kernel_args)
31 parser.addHandler('gli-profile/dns-servers', self.set_dns_servers)
32 parser.addHandler('gli-profile/portage-tree-sync', self.set_portage_tree_sync_type)
33 parser.addHandler('gli-profile/install-pcmcia-cs', self.set_install_pcmcia_cs)
34 parser.addHandler('gli-profile/default-gateway', self.set_default_gateway)
35 parser.addHandler('gli-profile/kernel-bootsplash', self.set_kernel_bootsplash)
36 parser.addHandler('gli-profile/cron-daemon', self.set_cron_daemon_pkg)
37 parser.addHandler('gli-profile/root-pass-hash', self.set_root_pass_hash)
38 parser.addHandler('gli-profile/kernel-config', self.set_kernel_config_uri)
39 parser.addHandler('gli-profile/domainname', self.set_domainname)
40 parser.addHandler('gli-profile/portage-snapshot', self.set_portage_tree_snapshot_uri)
41 parser.addHandler('gli-profile/time-zone', self.set_time_zone)
42 parser.addHandler('gli-profile/boot-loader_mbr', self.set_boot_loader_mbr)
43 parser.addHandler('gli-profile/nisdomainname', self.set_nisdomainname)
44 parser.addHandler('gli-profile/install-stage', self.set_install_stage)
45 parser.addHandler('gli-profile/boot-loader', self.set_boot_loader_pkg)
46 parser.addHandler('gli-profile/install-rp-pppoe', self.set_install_rp_pppoe)
47 parser.addHandler('gli-profile/kernel-source', self.set_kernel_source_pkg)
48 parser.addHandler('gli-profile/hostname', self.set_hostname)
49 parser.addHandler('gli-profile/logging-daemon', self.set_logging_daemon_pkg)
50 parser.addHandler('gli-profile/kernel-modules/module', self.add_kernel_module)
51 parser.addHandler('gli-profile/users/user', self.add_user)
52 parser.addHandler('gli-profile/make-conf/variable', self.make_conf_add_var)
53 parser.addHandler('gli-profile/rc-conf/variable', self.rc_conf_add_var)
54 parser.addHandler('gli-profile/network-interfaces/device', self.add_network_interface)
55 parser.addHandler('gli-profile/install-packages', self.set_install_packages)
56 parser.addHandler('gli-profile/fstab/partition', self.add_fstab_partition)
57 parser.addHandler('gli-profile/partitions/device', self.add_partitions_device, call_on_null=True)
58 parser.addHandler('gli-profile/partitions/device/partition', self.add_partitions_device_partition, call_on_null=True)
59 parser.addHandler('gli-profile/mta', self.set_mta)
60 parser.addHandler('gli-profile/network-mounts/netmount', self.add_netmount, call_on_null=True)
61 parser.addHandler('gli-profile/services', self.set_services)
62 parser.addHandler('gli-profile/grp-install', self.set_grp_install)
63
64 self._parser = parser
65
66 # Configuration information - profile data
67 self._cron_daemon_pkg = ""
68 self._logging_daemon_pkg = ""
69 self._boot_loader_mbr = True
70 self._boot_loader_pkg = ""
71 self._kernel_modules = []
72 self._kernel_config_uri = ""
73 self._kernel_args = ""
74 self._kernel_initrd = True
75 self._kernel_bootsplash = False
76 self._kernel_source_pkg = ""
77 self._users = []
78 self._root_pass_hash = ""
79 self._time_zone = ""
80 self._stage_tarball_uri = ""
81 self._install_stage = 1
82 self._portage_tree_sync_type = "sync"
83 self._portage_tree_snapshot_uri = ""
84 self._domainname = "localdomain"
85 self._hostname = "localhost"
86 self._nisdomainname = ""
87 self._partition_tables = {}
88 self._network_mounts = []
89 self._temp_partition_table = {}
90 self._network_interfaces = {}
91 self._make_conf = {}
92 self._rc_conf = {}
93 self._install_rp_pppoe = False
94 self._filesystem_tools = ()
95 self._install_pcmcia_cs = False
96 self._dns_servers = ()
97 self._default_gateway = ()
98 self._fstab = {}
99 self._install_packages = ()
100 self._services = ()
101 self._mta = ""
102 self._grp_install = False
103
104 def parse(self, filename):
105 self._parser.parse(filename)
106
107 def get_cron_daemon_pkg(self):
108 "returns cron_daemon_pkg"
109 return self._cron_daemon_pkg
110
111 def set_cron_daemon_pkg(self, xml_path, cron_daemon_pkg, xml_attr):
112 "cron_daemon_pkg is a string to determine which cron daemon to install and configure (ie. 'vixie-cron')"
113
114 # Check data type
115 if type(cron_daemon_pkg) != str:
116 raise GLIException("CronDaemonPKGError", 'fatal', 'set_cron_daemon_pkg', "Input must be type 'string'!")
117
118 self._cron_daemon_pkg = cron_daemon_pkg
119
120 def get_logging_daemon_pkg(self):
121 "returns logging_daemon_pkg"
122 return self._logging_daemon_pkg
123
124 def set_logging_daemon_pkg(self, xml_path, logging_daemon_pkg, xml_attr):
125 "logging_daemon_pkg is a string to determine which logging daemon to install and configure (ie. 'sysklogd')"
126
127 # Check data type
128 if type(logging_daemon_pkg) != str:
129 raise GLIException("LoggingDaemonPKGError", 'fatal', 'set_logging_daemon_pkg', "Input must be type 'string'!")
130
131 self._logging_daemon_pkg = logging_daemon_pkg
132
133 def get_boot_loader_mbr(self):
134 "returns boot_loader_mbr"
135 return self._boot_loader_mbr
136
137 def set_boot_loader_mbr(self, xml_path, boot_loader_mbr, xml_attr):
138 "boot_loader_mbr is a bool. True installs boot loader to MBR. False installs boot loader to the boot or root partition."
139
140 # Check data type
141 if type(boot_loader_mbr) != bool:
142 if type(boot_loader_mbr) == str:
143 boot_loader_mbr = GLIUtility.strtobool(boot_loader_mbr)
144 else:
145 raise GLIException("BootLoaderMBRError", 'fatal', 'set_boot_loader_mbr', "Input must be type 'bool'!")
146
147 self._boot_loader_mbr = boot_loader_mbr
148
149 def get_boot_loader_pkg(self):
150 "returns boot_loader_pkg"
151 return self._boot_loader_pkg
152
153 def set_boot_loader_pkg(self, xml_path, boot_loader_pkg, xml_attr):
154 "boot_loader_pkg is a string to decide which boot loader to install. (ie. 'grub')"
155
156 # Check data type
157 if type(boot_loader_pkg) != str:
158 raise GLIException("BootLoaderPKG", 'fatal', 'set_boot_loader_pkg', "Input must be type 'string'!")
159
160 self._boot_loader_pkg = boot_loader_pkg
161
162 def get_kernel_modules(self):
163 "returns kernel_modules"
164 return self._kernel_modules
165
166 def add_kernel_module(self, xml_path, kernel_module, xml_attr):
167 "Add a kernel module to the list of kernel modules"
168
169 if type(kernel_module) != str:
170 raise GLIException("KernelModuleError", 'fatal', 'add_kernel_module', "The kernel module must be a string!")
171
172 self._kernel_modules.append(kernel_module)
173
174 def set_kernel_modules(self, kernel_modules):
175 "kernel_modules is a tuple of strings containing names of modules to automatically load at boot time. (ie. '( 'ide-scsi', )')"
176
177 # Check type
178 if type(kernel_modules) != tuple:
179 raise GLIException("KernelModulesError", 'fatal', 'set_kernel_modules', "Must be a tuple!")
180
181 self._kernel_modules = []
182
183 # Check tuple data type
184 for module in kernel_modules:
185 self._add_kernel_module(module)
186
187 def get_kernel_config_uri(self):
188 "returns kernel_config_uri"
189 return self._kernel_config_uri
190
191 def set_kernel_config_uri(self, xml_path, kernel_config_uri, xml_attr):
192 "kernel_config_uri is a string that is the path to the kernel config file you wish to use. Can also be a http:// or ftp:// path."
193
194 # Check type
195 if type(kernel_config_uri) != str:
196 raise GLIException("KernelConfigURIError", 'fatal', 'set_kernel_config_uri', "Must be a string!")
197
198 # Check validity (now done in the FE)
199 #if not (kernel_config_uri):
200 # raise GLIException("KernelConfigURIError", 'fatal', 'set_kernel_config_uri', "Empty Kernel URI!")
201
202 self._kernel_config_uri = kernel_config_uri
203
204 def get_kernel_args(self):
205 "returns kernel arguments"
206 return self._kernel_args
207
208 def set_kernel_args(self, xml_path, kernel_args, xml_attr):
209 "kernel_args are the arguments to pass the kernel at boot from the bootloader."
210 self._kernel_args = kernel_args
211
212 def get_kernel_initrd(self):
213 "returns kernel_initrd"
214 return self._kernel_initrd
215
216 def set_kernel_initrd(self, xml_path, kernel_initrd, xml_attr):
217 "kernel_initrd is a bool to determine whether or not to build an initrd kernel. False builds a non-initrd kernel. (overwritten by kernel_bootsplash; needs genkernel non-initrd support not yet present)"
218
219 # Check type
220 if type(kernel_initrd) != bool:
221 if type(kernel_initrd) == str:
222 kernel_initrd = GLIUtility.strtobool(kernel_initrd)
223 else:
224 raise GLIException("KernelInitRDError", 'fatal', 'set_kernel_initrd', "Must be a bool!")
225
226 self._kernel_initrd = kernel_initrd
227
228 def get_kernel_bootsplash(self):
229 "returns kernel_bootsplash"
230 return self._kernel_bootsplash
231
232 def set_kernel_bootsplash(self, xml_path, kernel_bootsplash, xml_attr):
233 "kernel_bootsplash is a bool to determine whether or not to install bootsplash into the kernel. True builds in bootsplash support to the initrd. WARNING: kernel_source_pkg must contain a kernel with bootsplash support or the bootsplash will not appear. If you set this to true, it will build an initrd kernel even if you chose false for kernel_initrd!"
234
235 # Check type
236 if type(kernel_bootsplash) != bool:
237 if type(kernel_bootsplash) == str:
238 kernel_bootsplash = GLIUtility.strtobool(kernel_bootsplash)
239 else:
240 raise GLIException("KernelBootsplashError", 'fatal', 'set_kernel_bootsplash', "Must be a bool!")
241
242 self._kernel_bootsplash = kernel_bootsplash
243
244 def get_kernel_source_pkg(self):
245 "returns kernel_source_pkg"
246 return self._kernel_source_pkg
247
248 def set_kernel_source_pkg(self, xml_path, kernel_source_pkg, xml_attr):
249 "kernel_source_pkg is a string to define which kernel source to use. (ie. 'gentoo-sources')"
250
251 # Check type
252 if type(kernel_source_pkg) != str:
253 raise GLIException("KernelSourcePKGError", 'fatal', 'set_kernel_source_pkg', "Must be a string!")
254
255 self._kernel_source_pkg = kernel_source_pkg
256
257 def get_users(self):
258 "returns users"
259 return self._users
260
261 def add_user(self, xml_path, username, attr=None):
262 """
263 This will take a username (that is a string) and a set of attributes and it will verify everything is valid
264 and convert it into a 7-tuple set. Then it adds this tuple into the users list.
265 username and hash are manditory. All other attributes are optional. Or this method will
266 take a 7-tuple set, verify it's correctness and then append it to the _users list.
267 All items are strings except <uid>, which is an integer, and groups, which is a tuple.
268
269 The finished tuples look like this:
270 ( <user name>, <password hash>, (<tuple of groups>), <shell>, <home directory>, <user id>, <user comment> )
271
272 """
273 hash = ''
274 shell = None
275 groups = None
276 shell = None
277 homedir = None
278 uid = None
279 comment = None
280
281 if type(username) == tuple:
282 if len(username) != 7:
283 raise GLIException("UserError", 'fatal', 'add_user', "Wrong format for user tuple!")
284
285 username_tmp = username[0]
286 hash = username[1]
287 groups = username[2]
288 shell = username[3]
289 homedir = username[4]
290 uid = username[5]
291 comment = username[6]
292 username = username_tmp
293
294 if type(groups) != tuple:
295 if groups != None:
296 groups = tuple(groups.split(','))
297 else:
298 for attrName in attr.keys():
299 if attrName == 'groups':
300 groups = tuple(str(attr[attrName]).split(','))
301 elif attrName == 'shell':
302 shell = str(attr[attrName])
303 elif attrName == 'hash':
304 hash = str(attr[attrName])
305 elif attrName == 'homedir':
306 homedir = str(attr[attrName])
307 elif attrName == 'uid':
308 if attr[attrName]:
309 uid = int(attr[attrName])
310 elif attrName == 'comment':
311 comment = str(attr[attrName])
312
313 allowable_nonalphnum_characters = '_-'
314
315 if not GLIUtility.is_realstring(username):
316 raise GLIException("UserError", 'fatal', 'add_user', "username must be a non-empty string")
317
318 if username[0] not in (string.lowercase + string.uppercase):
319 raise GLIException("UsersError", 'fatal', 'add_user', "A username must start with a letter!")
320
321 for x in username:
322 if x not in (string.lowercase + string.uppercase + string.digits + allowable_nonalphnum_characters):
323 raise GLIException("UsersError", 'fatal', 'add_user', "A username must contain only letters, numbers, or these symbols: " + allowable_nonalphnum_characters)
324
325 for user in self._users:
326 if username == user[0]:
327 raise GLIException("UserError", 'fatal', 'add_user', "This username already exists!")
328
329 if (hash == None) or (hash == ''):
330 raise GLIException("UserError", 'fatal', 'add_user', "A password hash must be given for every user!")
331
332 self._users.append((username,hash,groups,shell,homedir,uid,comment))
333
334 def remove_user(self, username):
335 """
336 Remove "username" from the _users list.
337 """
338 for user in self._users:
339 if username == user[0]:
340 self._users.remove(user)
341 break
342
343 def set_users(self, users):
344 """
345 users is a tuple(user) of tuple's. This sets _users to this set of tuples.
346 """
347 self._users = []
348
349 if users != None:
350 for user in users:
351 #self.add_user(user) not sure what someone was doing here. remove later if not needed
352 self._users.append(user)
353
354 def get_root_pass_hash(self):
355 "returns root_pass_hash"
356 return self._root_pass_hash
357
358 def set_root_pass_hash(self, xml_path, root_pass_hash, xml_attr):
359 "root_pass_hash is a string containing an md5 password hash to be assinged as the password for the root user."
360
361 # Check type
362 if type(root_pass_hash) != str:
363 raise GLIException("RootPassHashError", 'fatal', 'set_root_pass_hash', "Must be a string!")
364
365 self._root_pass_hash = root_pass_hash
366
367 def get_time_zone(self):
368 "returns time_zone"
369 return self._time_zone
370
371 def set_time_zone(self, xml_path, time_zone, xml_attr):
372 "time_zone is a string defining the time zone to use. Time zones are found in /usr/share/zoneinfo/. Syntax is 'UTC' or 'US/Eastern'."
373
374 # Check type
375 if type(time_zone) != str:
376 raise GLIException("TimeZoneError", 'fatal', 'set_time_zone', "Must be a string!")
377
378 self._time_zone = time_zone
379
380 def get_stage_tarball_uri(self):
381 "returns stage_tarball_uri"
382 return self._stage_tarball_uri
383
384 def set_stage_tarball_uri(self, xml_path, stage_tarball_uri, xml_attr):
385 "stage_tarball_uri is a string that is the full path to the tarball you wish to use. (ie. 'file:///path/to/mytarball.tar.bz2')"
386
387 # Check type
388 if type(stage_tarball_uri) != str:
389 raise GLIException("StageTarballURIError", 'fatal', 'set_stage_tarball_uri', "Must be a string!")
390
391 # Check validity (now done in the FE)
392 #if not stage_tarball_uri:
393 # raise GLIException("CustomStage3TarballURIError", 'fatal', 'set_stage_tarball_uri', "Empty URI!")
394
395 self._stage_tarball_uri = stage_tarball_uri
396
397 def get_install_stage(self):
398 "returns install_stage"
399 return self._install_stage
400
401 def set_install_stage(self, xml_path, install_stage, xml_attr):
402 "install_stage is a integer to define which stage install to use. Appropriate stages are 1-3."
403
404 # Check type
405 if type(install_stage) != int:
406 if type(install_stage) == str:
407 install_stage = int(install_stage)
408 else:
409 raise GLIException("InstallStageError", 'fatal', 'set_install_stage', "Must be an integer!")
410
411 # Check for stage bounds
412 if 0 < install_stage < 4:
413 self._install_stage = install_stage
414 else:
415 raise GLIException("InstallStageError", 'fatal', 'set_install_stage', "install_stage must be 1-3!")
416
417 def get_portage_tree_sync_type(self):
418 "returns portage_tree_sync"
419 return self._portage_tree_sync_type
420
421 def set_portage_tree_sync_type(self, xml_path, portage_tree_sync, xml_attr):
422 "portage_tree_sync is a bool to determine whether or not to run 'emerge sync' to get the latest portage tree."
423
424 # Check type
425 if type(portage_tree_sync) != str:
426 raise GLIException("PortageTreeSyncError", 'fatal', 'set_portage_tree_sync_type', "Must be a string!")
427
428 if string.lower(portage_tree_sync) not in ('sync', 'webrsync', 'custom'):
429 raise GLIException("PortageTreeSyncError", 'fatal', 'set_portage_tree_sync_type', "Invalid Input!")
430
431 self._portage_tree_sync_type = string.lower(portage_tree_sync)
432
433 def get_portage_tree_snapshot_uri(self):
434 "returns portage_tree_snapshot_uri"
435 return self._portage_tree_snapshot_uri
436
437 def set_portage_tree_snapshot_uri(self, xml_path, portage_tree_snapshot_uri, xml_attr):
438 "portage_tree_snapshot_uri is a string defining the path to a portage tree snapshot. (ie. 'file:///mnt/cdrom/snapshots/portage-*.tar.bz2')"
439
440 # Check type
441 if type(portage_tree_snapshot_uri) != str:
442 raise GLIException("PortageTreeSnapshotURIError", 'fatal', 'set_portage_tree_snapshot_uri', "Must be a string!")
443
444 # Check validity (now done in the FE)
445 #if not portage_tree_snapshot_uri:
446 # raise GLIException("PortageTreeSnapshotURIError", 'fatal', 'set_portage_tree_snapshot_uri', "Invalid URI!")
447
448 self._portage_tree_snapshot_uri = portage_tree_snapshot_uri
449
450 def get_domainname(self):
451 "returns domainname"
452 return self._domainname
453
454 def set_domainname(self, xml_path, domainname, xml_attr):
455 "domainname is a string containing the domainname for the new system. (ie. 'mydomain.com'; NOT FQDN)"
456
457 # Check type
458 if type(domainname) != str:
459 raise GLIException("DomainnameError", 'fatal', 'set_domainname', "Must be a string!")
460
461 self._domainname = domainname
462
463 def get_hostname(self):
464 "returns hostname"
465 return self._hostname
466
467 def set_hostname(self, xml_path, hostname, xml_attr):
468 "hostname is a string containing the hostname for the new system. (ie. 'myhost'; NOT 'myhost.mydomain.com')"
469
470 # Check type
471 if type(hostname) != str:
472 raise GLIException("HostnameError", 'fatal', 'set_hostname', "Must be a string!")
473
474 self._hostname = hostname
475
476 def get_nisdomainname(self):
477 "returns nisdomainname"
478 return self._nisdomainname
479
480 def set_nisdomainname(self, xml_path, nisdomainname, xml_attr):
481 "nisdomainname is a string containing the NIS domainname for the new system."
482
483 # Check type
484 if type(nisdomainname) != str:
485 raise GLIException("NISDomainnameError", 'fatal', 'set_nisdomainname', "Must be a string!")
486
487 self._nisdomainname = nisdomainname
488
489 def get_partition_tables(self):
490 "returns partition_tables"
491 return self._partition_tables
492
493 def set_partition_tables(self, partition_tables):
494 """
495 Sets the partition tables. A partition is a multi level dictionary in the following format:
496 { <device (local)>: <partition table>, <device (nfs)>: <mount point> }
497
498 <device (local)> is a string containing the path to the local file. (ie. '/dev/hda')
499 <device (nfs)> is a string containing the ip address of the nfs mount. (ie. '192.168.1.2')
500
501 <partition table> is a dictionary in the following format:
502 { <minor>: { 'mb': <size in mb>, 'type': <type>, 'mountpoint': <mount point>, 'start': <start cylinder>,
503 'end': <end cylinder>, 'mountopts': <mount options>, 'format': <format> } }
504
505 ie. partition_tables['/dev/hda'][1] would return { 'mb': 0, 'type': 'ext3', 'mountpoint': '/boot', 'start': 12345,
506 'end': 34567, 'mountopts': 'auto', format: 'False' }
507
508 Types are as follows:
509 string: <device>, <mount point>, <mount options>, <type>
510 integer: <minor>, <size in mb>, <start cylinder>, <end cylinder>
511 boolean: <format>
512
513 Current <type> options include:
514 ext2, ext3, reiserfs, xfs, jfs, linux-swap, extended, others?
515
516 There will be a method in the partitioning code to make sure that the current parition_tables can actually be implemented.
517 Should we call that function to test the culpability of our potential partitioning scheme?
518 Should we create a method in the Controller to take raw variables and put them in the proper structure?
519 Are all filesystems supported by all arches?
520 """
521
522 if type(partition_tables) != dict:
523 raise GLIException("PartitionTableError", 'fatal', 'set_partition_tables', "Invalid data type! partition_tables is a dict...")
524
525 for device in partition_tables:
526
527 # If the device is a valid local device...
528 if GLIUtility.is_device(device):
529
530 # We should check to make sure device is in /proc/partitions
531 # If it is in /proc/partitions, it is a partitionable device
532
533 # ... then loop through each minor to check data
534 for minor in partition_tables[device]:
535
536 # Make sure that the <minor> is an integer or can be converted to one
537 try:
538 int(minor)
539 except:
540 raise GLIException("ParitionTableError", 'fatal', 'set_partition_tables', "The minor you specified (" + minor + ") is not an integer!")
541
542 # Make sure that a minor number is valid
543 if minor < 1:
544 raise GLIException("ParitionTableError", 'fatal', 'set_partition_tables', "The minor you specified (" + minor + ") is not a valid minor!")
545
546 # Make sure that <size>, <type> and <mount point> are all set
547 #if len(partition_tables[device][minor]) != 3:
548 # raise GLIException("ParitionTableError", 'fatal', 'set_partition_tables', "The number of attributes for minor " + minor + " is incorrect!")
549 #
550 # Make sure that the <size> is an integer or can be converted to one
551 #try:
552 # int(partition_tables[device][minor][0])
553 #except:
554 # raise GLIException("ParitionTableError", 'fatal', 'set_partition_tables', "The size you specified (" + partition_tables[device][minor][0] + ") is not an integer!")
555
556 # Else, if the device is a valid remote device (hostname or ip)
557 elif GLIUtility.is_ip(device) or GLIUtility.is_hostname(device):
558
559 pass
560 # Make sure that only the mount point is set
561 # if type(partition_tables[device]) != str:
562 # raise GLIException("ParitionTableError", 'fatal', 'set_partition_tables', "Invalid mount point for nfs mount (device: " + device + ")!")
563
564 # If the device is not a local or remote device, then it is invalid
565 else:
566 raise GLIException("PartitionTableError", 'fatal', 'set_partition_tables', "The device you specified (" + device + ") is not valid!")
567
568 # If all the tests clear, then set the variable
569 self._partition_tables = partition_tables
570
571
572 def get_network_interfaces(self):
573 "Returns network_interfaces"
574 return self._network_interfaces
575
576 def add_network_interface(self, xml_path, device, attr):
577 """
578 This adds an ethernet device to the _network_interfaces dictionary.
579 The format of this dictionary is:
580 { <eth_device> : (options tuple), ... }
581
582 The format of the options tuple is:
583 ( <ip address>, <broadcast>, <netmask> )
584
585 If the user wants to use DHCP, the <ip address> will be set to 'dhcp'
586 and broadcast and netmask will both be set to None.
587
588 Aliases are no longer needed in the tuple because they can be treated like
589 an individual interface. GLIUtility.is_eth_device will recogniz
590 """
591 options = None
592 ip = broadcast = netmask = None
593 dhcp = True
594
595 if type(device) != str:
596 raise GLIException("NetworkInterfacesError", 'fatal', 'add_network_interface', "Invalid or unimplimented device type (" + device + ")!")
597
598 if not GLIUtility.is_eth_device(device):
599 raise GLIException("NetworkInterfacesError", 'fatal', 'add_network_interface', "Invalid or unimplimented device type (" + device + ")!")
600
601 if type(attr) == tuple:
602 ip = attr[0]
603 broadcast = attr[1]
604 netmask = attr[2]
605 if ip != 'dhcp':
606 dhcp = False
607 else:
608 if "ip" in attr.getNames():
609 for attrName in attr.keys():
610 if attrName == 'ip':
611 ip = str(attr[attrName])
612 elif attrName == 'broadcast':
613 broadcast = str(attr[attrName])
614 elif attrName == 'netmask':
615 netmask = str(attr[attrName])
616 dhcp = False
617
618 if not dhcp:
619 if not GLIUtility.is_ip(ip):
620 raise GLIException("NetworkInterfacesError", 'fatal', 'add_network_interface', "The ip address you specified for " + device + " is not valid!")
621 if not GLIUtility.is_ip(broadcast):
622 raise GLIException("NetworkInterfacesError", 'fatal', 'add_network_interface', "The broadcast address you specified for " + device + " is not valid!")
623 if not GLIUtility.is_ip(netmask):
624 raise GLIException("NetworkInterfacesError", 'fatal', 'add_network_interface', "The netmask address you specified for " + device + " is not valid!")
625 options = (ip, broadcast, netmask)
626 else:
627 options = ('dhcp', None, None)
628
629 self._network_interfaces[device] = options
630
631 def set_network_interfaces(self, network_interfaces):
632 """
633 This method sets the network interfaces diction to network_interfaces.
634 This method uses the function add_network_interfaces to do all of the
635 real work.
636 """
637
638 # Check type
639 if type(network_interfaces) != dict:
640 raise GLIException("NetworkInterfacesError", 'fatal', 'set_network_interfaces', "Must be a dictionary!")
641
642 self._network_interfaces = {}
643 for device in network_interfaces:
644 self.add_network_interface(None, device, network_interfaces[device])
645
646 def serialize(self):
647 """
648 This method serializes the configuration data and output a nice XML document.
649
650 NOTE: this method currently does not serialize: _partition_tables or _kernel_modules
651
652 """
653 import xml.dom.minidom
654 xmldoc = ""
655 xmltab = { 'cron-daemon': self.get_cron_daemon_pkg,
656 'logging-daemon': self.get_logging_daemon_pkg,
657 'boot-loader_mbr': self.get_boot_loader_mbr,
658 'boot-loader': self.get_boot_loader_pkg,
659 'kernel-config': self.get_kernel_config_uri,
660 'kernel-initrd': self.get_kernel_initrd,
661 'kernel-args': self.get_kernel_args,
662 'kernel-bootsplash': self.get_kernel_bootsplash,
663 'kernel-source': self.get_kernel_source_pkg,
664 'root-pass-hash': self.get_root_pass_hash,
665 'time-zone': self.get_time_zone,
666 'stage-tarball': self.get_stage_tarball_uri,
667 'install-stage': self.get_install_stage,
668 'portage-tree-sync': self.get_portage_tree_sync_type,
669 'portage-snapshot': self.get_portage_tree_snapshot_uri,
670 'domainname': self.get_domainname,
671 'hostname': self.get_hostname,
672 'nisdomainname': self.get_nisdomainname,
673 'install-rp-pppoe': self.get_install_rp_pppoe,
674 'install-pcmcia-cs': self.get_install_pcmcia_cs,
675 'mta': self.get_mta,
676 'grp-install': self.get_grp_install,
677 }
678
679 xmldoc += "<?xml version=\"1.0\"?>"
680
681 xmldoc += "<gli-profile>"
682
683 # Normal cases
684 for key in xmltab.keys():
685 xmldoc += "<%s>%s</%s>" % (key, xmltab[key](), key)
686
687 # Other cases
688 if self.get_users() != []:
689 xmldoc += "<users>"
690 users = self.get_users()
691 for user in users:
692 attrstr = ""
693 username = user[0]
694
695 if user[1] != None:
696 attrstr += "hash=\"%s\" " % user[1]
697 if user[2] != None:
698 attrstr += "groups=\"%s\" " % string.join(user[2],',')
699 if user[3] != None:
700 attrstr += "shell=\"%s\" " % user[3]
701 if user[4] != None:
702 attrstr += "homedir=\"%s\" " % user[4]
703 if user[5] != None:
704 attrstr += "uid=\"%s\" " % user[5]
705 if user[6] != None:
706 attrstr += "comment=\"%s\" " % user[6]
707
708 xmldoc += "<user %s>%s</user>" % (string.strip(attrstr), username)
709 xmldoc += "</users>"
710
711 if self.get_make_conf() != {}:
712 xmldoc += "<make-conf>"
713
714 make_conf = self.get_make_conf()
715 for var in make_conf:
716 xmldoc += "<variable name=\"%s\">%s</variable>" % (var, make_conf[var])
717
718 xmldoc += "</make-conf>"
719
720 if self.get_rc_conf() != {}:
721 xmldoc += "<rc-conf>"
722
723 rc_conf = self.get_rc_conf()
724 for var in rc_conf:
725 xmldoc += "<variable name=\"%s\">%s</variable>" % (var, rc_conf[var])
726
727 xmldoc += "</rc-conf>"
728
729 if self.get_dns_servers() != ():
730 xmldoc += "<dns-servers>"
731 xmldoc += string.join(self.get_dns_servers(), ' ')
732 xmldoc += "</dns-servers>"
733
734 if self.get_network_interfaces() != {}:
735 xmldoc += "<network-interfaces>"
736 interfaces = self.get_network_interfaces()
737 for iface in interfaces:
738 if interfaces[iface][0] == 'dhcp':
739 xmldoc += "<device>%s</device>" % iface
740 else:
741 xmldoc += "<device ip=\"%s\" broadcast=\"%s\" netmask=\"%s\">%s</device>" % (interfaces[iface][0], interfaces[iface][1], interfaces[iface][2], iface)
742 xmldoc += "</network-interfaces>"
743
744 if self.get_kernel_modules() != []:
745 kernel_modules = self.get_kernel_modules()
746 xmldoc += "<kernel-modules>";
747 for module in kernel_modules:
748 xmldoc += "<module>%s</module>" % module
749 xmldoc += "</kernel-modules>";
750
751 if self.get_fstab() != {}:
752 xmldoc += "<fstab>"
753 partitions = self.get_fstab()
754 for part in partitions:
755 xmldoc += "<partition dev=\"%s\" fstype=\"%s\" options=\"%s\">%s</partition>" % (partitions[part][0],partitions[part][1],partitions[part][2],part)
756 xmldoc += "</fstab>"
757
758 if self.get_install_packages() != ():
759 xmldoc += "<install-packages>"
760 xmldoc += string.join(self.get_install_packages(), ' ')
761 xmldoc += "</install-packages>"
762
763 if self.get_services() != ():
764 xmldoc += "<services>"
765 xmldoc += string.join(self.get_services(), ' ')
766 xmldoc += "</services>"
767
768 if self.get_default_gateway() != ():
769 gw = self.get_default_gateway()
770 xmldoc += "<default-gateway interface=\"%s\">%s</default-gateway>" % (gw[0], gw[1])
771
772 if self.get_partition_tables() != {}:
773 partitions = self.get_partition_tables()
774 xmldoc += "<partitions>";
775 for device in partitions.keys():
776 xmldoc += "<device devnode=\"%s\">" % device
777 for minor in partitions[device]:
778 part = partitions[device][minor]
779 xmldoc += "<partition minor=\"%s\" origminor=\"%s\" mb=\"%s\" type=\"%s\" mountpoint=\"%s\" start=\"%s\" end=\"%s\" mountopts=\"%s\" format=\"%s\" />" % (str(minor), str(part['origminor']), str(part['mb']), str(part['type']), str(part['mountpoint']), str(part['start']), str(part['end']), str(part['mountopts']), str(part['format']))
780 xmldoc += "</device>"
781 xmldoc += "</partitions>"
782
783 if self.get_network_mounts() != {}:
784 netmounts = self.get_network_mounts()
785 xmldoc += "<network-mounts>"
786 for mount in netmounts:
787 xmldoc += "<netmount host=\"%s\" export=\"%s\" type=\"%s\" mountpoint=\"%s\" mountopts=\"%s\" />" % (mount['host'], mount['export'], mount['type'], mount['mountpoint'], mount['mountopts'])
788 xmldoc += "</network-mounts>"
789
790 xmldoc += "</gli-profile>"
791
792 dom = xml.dom.minidom.parseString(xmldoc)
793 return dom.toprettyxml()
794
795 def make_conf_add_var(self, xml_path, data, attr):
796 """
797 data is a string that is the value of the variable name.
798 attr is an xml attribute that contains the name of the variable
799 OR attr is a variable name, like 'USE'. This makes it easier for front-end designers.
800 """
801 if type(attr) == 'str':
802 self._make_conf[attr] = str(data)
803 else:
804 if 'name' not in attr.keys():
805 raise GLIException("MakeConfError", 'fatal', 'make_conf_add_var', "Every value needs to have a variable name!")
806
807 varName = attr['name']
808 self._make_conf[str(varName)] = str(data)
809
810 def set_make_conf(self, make_conf):
811 """
812 make_conf is a dictionary that will be set to _make_conf
813
814 There is no checking that needs to be done, so please sure sure that the make_conf dictionary
815 that is passed in is valid.
816 """
817
818 self._make_conf = make_conf
819
820 def get_make_conf(self):
821 """ Return a dictionary of the make.conf """
822 return self._make_conf
823
824 def rc_conf_add_var(self, xml_path, data, attr):
825 """
826 data is a string that is the value of the variable name.
827 attr is an xml attribute that contains the name of the variable
828 """
829 if 'name' not in attr.keys():
830 raise GLIException("RCConfError", 'fatal', 'rc_conf_add_var', "Every value needs to have a variable name!")
831
832 varName = attr['name']
833 self._rc_conf[str(varName)] = str(data)
834
835 def set_rc_conf(self, rc_conf):
836 """
837 rc_conf is a dictionary that will be set to _rc_conf
838
839 There is no checking that needs to be done, so please sure sure that the rc_conf dictionary
840 that is passed in is valid.
841 """
842
843 self._rc_conf = rc_conf
844
845 def get_rc_conf(self):
846 """ Return a dictionary of the make.conf """
847 return self._rc_conf
848
849 def set_install_rp_pppoe(self, xml_path, install_rp_pppoe, xml_attr):
850 """
851 Tell the installer whether or not to install the rp-pppoe package
852 """
853
854 if type(install_rp_pppoe) != bool:
855 if type(install_rp_pppoe) == str:
856 install_rp_pppoe = GLIUtility.strtobool(install_rp_pppoe)
857 else:
858 raise GLIException("InstallRP_PPPOE", 'fatal', 'set_install_rp_pppoe', "Invalid input!")
859
860 self._install_rp_pppoe = install_rp_pppoe
861
862 def get_install_rp_pppoe(self):
863 """ Return the boolean value of _install_rp_pppoe """
864 return self._install_rp_pppoe
865
866 def set_install_pcmcia_cs(self, xml_path, install_pcmcia, xml_attr):
867 """ This tells the installer whether or not to install the pcmcia_cs package """
868 if type(install_pcmcia) != bool:
869 if type(install_pcmcia) == str:
870 install_pcmcia = GLIUtility.strtobool(install_pcmcia)
871 else:
872 raise GLIException("InstallPcmciaCS", 'fatal', 'set_install_pcmcia_cs', "Input must be type 'bool'!")
873
874 self._install_pcmcia_cs = install_pcmcia
875
876 def get_install_pcmcia_cs(self):
877 """ Returns the boolean _install_pcmcia_cs """
878
879 return self._install_pcmcia_cs
880
881 def set_dns_servers(self, xml_path, dns_servers, xml_attr):
882 """
883 Set the DNS servers for the post-installed system.
884 """
885
886 if type(dns_servers) == tuple:
887 dns_servers = dns_servers[0:3]
888 elif type(dns_servers) == str:
889 dns_servers = string.split(dns_servers)
890 else:
891 raise GLIException("DnsServersError", 'fatal', 'set_dns_servers', "Invalid input!")
892
893 for server in dns_servers:
894 if not GLIUtility.is_ip(server):
895 raise GLIException("DnsServersError", 'fatal', 'set_dns_servers', server + " must be a valid IP address!")
896
897 self._dns_servers = dns_servers
898
899 def get_dns_servers(self):
900 """ This returns a tuple of the form:
901 (<nameserver 1>, <nameserver 2>, <nameserver 3>)
902 """
903 return self._dns_servers
904
905 def set_default_gateway(self, xml_path, gateway, xml_attr):
906 """
907 Set the default gateway for the post-installed system.
908 The format of the input is: <default-gateway interface="interface name">ip of gateway</default-gateway>
909 It saves this information in the following format: (<interface>, <ip of gateway>)
910 """
911
912 if not GLIUtility.is_realstring(gateway):
913 raise GLIException('DefaultGatewayError', 'fatal', 'set_default_gateway', "The gateway must be a non-empty string!")
914
915 if not 'interface' in xml_attr.keys():
916 raise GLIException('DefaultGatewayError', 'fatal', 'set_default_gateway', 'No interface information specified!')
917
918 interface = str(xml_attr['interface'])
919
920 if not GLIUtility.is_eth_device(interface):
921 raise GLIException('DefaultGatewayError', 'fatal', 'set_default_gateway', "Invalid device!")
922
923 if not GLIUtility.is_ip(gateway):
924 raise GLIException("DefaultGateway", 'fatal', 'set_default_gateway', "The IP Provided is not valid!")
925
926 self._default_gateway = (interface, gateway)
927
928 def get_default_gateway(self):
929 """
930 Returns the default gateway
931 """
932 return self._default_gateway
933
934
935 def add_fstab_partition(self, xml_path, mountpoint, attr):
936 """
937 This adds a partition to the list of partitions to be mounted in fstab.
938 the format should be:
939 <fstab>
940 <partition dev="/dev/hda1" fstype="ext3" options="nostuff, defaults">/</partition>
941 """
942 info = None
943 options = fstype = dev = None
944 if not GLIUtility.is_realstring(mountpoint):
945 raise GLIException("AddPartitionError", 'fatal', 'add_fstab_partition', "Invalid mountpoint or mountpoint does not exist!")
946
947
948 if type(attr) == tuple:
949 dev = attr[0]
950 fstype = attr[1]
951 options = attr[2]
952
953 else:
954 if "dev" in attr.getNames():
955 for attrName in attr.getNames():
956 if attrName == 'dev':
957 dev = str(attr.getValue(attrName))
958 elif attrName == 'fstype':
959 fstype = str(attr.getValue(attrName))
960 elif attrName == 'options':
961 options = str(attr.getValue(attrName))
962 info = (dev,fstype,options)
963 self._fstab[mountpoint] = info
964
965 def get_fstab(self):
966 """
967 Returns the fstab info.
968 """
969 return self._fstab
970
971 def set_install_packages(self, xml_path, install_packages, xml_attr):
972 """
973 Set the packages to be installed for the post-installed system.
974 """
975
976 if type(install_packages) == str:
977 install_packages = string.split(install_packages)
978 else:
979 raise GLIException("InstallPackagesError", 'fatal', 'set_install_packages', "Invalid input!")
980
981 for install_package in install_packages:
982 if not GLIUtility.is_realstring(install_package):
983 raise GLIException("InstallPackagesError", 'fatal', 'set_install_packages', install_package + " must be a valid string!")
984
985 self._install_packages = install_packages
986
987 def get_install_packages(self):
988 """
989 This returns a list of the packages:
990 """
991 return self._install_packages
992
993 def add_partitions_device(self, xml_path, unused, attr):
994 devnode = None
995 if type(attr) == tuple:
996 devnode = attr[0]
997 else:
998 if "devnode" in attr.getNames():
999 devnode = str(attr.getValue("devnode"))
1000 self._partition_current_device = devnode
1001 self._partition_tables[devnode] = self._temp_partition_table
1002 self._temp_partition_table = {}
1003
1004 def add_partitions_device_partition(self, xml_path, unused, attr):
1005 part_entry = {'end': 0, 'format': None, 'mb': 0, 'minor': 0, 'mountopts': '', 'mountpoint': '', 'origminor': '', 'start': 0, 'type': ''}
1006 if type(attr) == tuple:
1007 part_entry['end'] = attr[0]
1008 part_entry['format'] = attr[1]
1009 part_entry['mb'] = attr[2]
1010 part_entry['minor'] = attr[3]
1011 part_entry['mountopts'] = attr[4]
1012 part_entry['mountpoint'] = attr[5]
1013 part_entry['origminor'] = attr[6]
1014 part_entry['start'] = attr[7]
1015 part_entry['type'] = attr[8]
1016 else:
1017 if "minor" in attr.getNames():
1018 for attrName in attr.getNames():
1019 part_entry[attrName] = str(attr.getValue(attrName))
1020 if type(part_entry['format']) == str: part_entry['format'] = GLIUtility.strtobool(part_entry['format'])
1021 if GLIUtility.is_numeric(part_entry['end']): part_entry['end'] = int(part_entry['end'])
1022 if GLIUtility.is_numeric(part_entry['start']): part_entry['start'] = int(part_entry['start'])
1023 if GLIUtility.is_numeric(part_entry['mb']): part_entry['mb'] = int(part_entry['mb'])
1024 if GLIUtility.is_numeric(part_entry['minor']): part_entry['minor'] = int(part_entry['minor'])
1025 if GLIUtility.is_numeric(part_entry['origminor']): part_entry['origminor'] = int(part_entry['origminor'])
1026 self._temp_partition_table[part_entry['minor']] = part_entry
1027
1028 def set_mta(self, xml_path, mta, xml_attr):
1029 if type(mta) != str:
1030 raise GLIException("MTAError", 'fatal', 'set_mta', "The MTA must be a string!")
1031
1032 self._mta = mta
1033
1034 def get_mta(self):
1035 return self._mta
1036
1037 def add_netmount(self, xml_path, unused, attr):
1038 netmount_entry = {'export': '', 'host': '', 'mountopts': '', 'mountpoint': '', 'type': ''}
1039 if type(attr) == tuple:
1040 netmount_entry['export'] = attr[0]
1041 netmount_entry['host'] = attr[1]
1042 netmount_entry['mountopts'] = attr[2]
1043 netmount_entry['mountpoint'] = attr[3]
1044 netmount_entry['type'] = attr[4]
1045 else:
1046 if "export" in attr.getNames():
1047 for attrName in attr.getNames():
1048 netmount_entry[attrName] = str(attr.getValue(attrName))
1049 self._network_mounts.append(netmount_entry)
1050
1051 def set_network_mounts(self, netmounts):
1052 self._network_mounts = netmounts
1053
1054 def get_network_mounts(self):
1055 return self._network_mounts
1056 def set_services(self, xml_path, services, xml_attr):
1057 """
1058 Set the services to be started on bootup.
1059 """
1060
1061 if type(services) == str:
1062 services = string.split(services)
1063 else:
1064 raise GLIException("ServicesError", 'fatal', 'set_services', "Invalid input!")
1065
1066 for service in services:
1067 if not GLIUtility.is_realstring(service):
1068 raise GLIException("ServicesError", 'fatal', 'set_services', service + " must be a valid string!")
1069
1070 self._services = services
1071
1072 def get_services(self):
1073 """
1074 This returns a list of the packages:
1075 """
1076 return self._services
1077
1078 def get_grp_install(self):
1079 "returns grp_install"
1080 return self._grp_install
1081
1082 def set_grp_install(self, xml_path, grp_install, xml_attr):
1083 "grp_install is a bool. True installs GRP. False doesn't."
1084
1085 # Check data type
1086 if type(grp_install) != bool:
1087 if type(grp_install) == str:
1088 grp_install = GLIUtility.strtobool(grp_install)
1089 else:
1090 raise GLIException("GRPInstall", 'fatal', 'set_grp_install', "Input must be type 'bool'!")
1091
1092 self._grp_install = grp_install

Properties

Name Value
svn:eol-style native

  ViewVC Help
Powered by ViewVC 1.1.20