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

Contents of /trunk/src/GLIInstallProfile.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 268 - (show annotations) (download) (as text)
Wed Jan 19 06:17:03 2005 UTC (15 years, 10 months ago) by codeman
File MIME type: text/x-python
File size: 40945 byte(s)
Various fixes related to the add_users function.  Still not yet finished.

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

Properties

Name Value
svn:eol-style native

  ViewVC Help
Powered by ViewVC 1.1.20