1 |
# |
2 |
# kickstart.py: kickstart install support |
3 |
# |
4 |
# Copyright 1999-2004 Red Hat, Inc. |
5 |
# |
6 |
# This software may be freely redistributed under the terms of the GNU |
7 |
# library public license. |
8 |
# |
9 |
# You should have received a copy of the GNU Library Public License |
10 |
# along with this program; if not, write to the Free Software |
11 |
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
12 |
# |
13 |
|
14 |
import iutil |
15 |
import isys |
16 |
import os |
17 |
from installclass import BaseInstallClass |
18 |
from partitioning import * |
19 |
from autopart import * |
20 |
from fsset import * |
21 |
from flags import flags |
22 |
from constants import * |
23 |
import sys |
24 |
import raid |
25 |
import string |
26 |
import partRequests |
27 |
import urllib2 |
28 |
import lvm |
29 |
|
30 |
from rhpl.translate import _ |
31 |
from rhpl.log import log |
32 |
|
33 |
KS_MISSING_PROMPT = 0 |
34 |
KS_MISSING_IGNORE = 1 |
35 |
|
36 |
class KickstartError(Exception): |
37 |
def __init__(self, val = ""): |
38 |
self.value = val |
39 |
|
40 |
def __str__ (self): |
41 |
return self.value |
42 |
|
43 |
class KickstartValueError(KickstartError): |
44 |
def __init__(self, val = ""): |
45 |
self.value = val |
46 |
|
47 |
def __str__ (self): |
48 |
return self.value |
49 |
|
50 |
class KSAppendException(KickstartError): |
51 |
def __init__(self, s=""): |
52 |
self.str = s |
53 |
|
54 |
def __str__(self): |
55 |
return self.str |
56 |
|
57 |
class Script: |
58 |
def __repr__(self): |
59 |
str = ("(s: '%s' i: %s c: %d)") % \ |
60 |
(self.script, self.interp, self.inChroot) |
61 |
return string.replace(str, "\n", "|") |
62 |
|
63 |
def __init__(self, script, interp, inChroot, logfile = None): |
64 |
self.script = script |
65 |
self.interp = interp |
66 |
self.inChroot = inChroot |
67 |
self.logfile = logfile |
68 |
|
69 |
def run(self, chroot, serial): |
70 |
scriptRoot = "/" |
71 |
if self.inChroot: |
72 |
scriptRoot = chroot |
73 |
|
74 |
path = scriptRoot + "/tmp/ks-script" |
75 |
|
76 |
f = open(path, "w") |
77 |
f.write(self.script) |
78 |
f.close() |
79 |
os.chmod(path, 0700) |
80 |
|
81 |
if self.logfile is not None: |
82 |
messages = self.logfile |
83 |
elif serial: |
84 |
messages = "/tmp/ks-script.log" |
85 |
else: |
86 |
messages = "/dev/tty3" |
87 |
|
88 |
rc = iutil.execWithRedirect(self.interp, |
89 |
[self.interp,"/tmp/ks-script"], |
90 |
stdout = messages, stderr = messages, |
91 |
root = scriptRoot) |
92 |
|
93 |
if rc != 0: |
94 |
log("WARNING - Error code %s encountered running a kickstart %%pre/%%post script", rc) |
95 |
|
96 |
os.unlink(path) |
97 |
|
98 |
class KickstartBase(BaseInstallClass): |
99 |
name = "kickstart" |
100 |
|
101 |
def postAction(self, rootPath, serial, intf): |
102 |
win = intf.waitWindow(_("Post Install Script"), |
103 |
_("The post installation script is running...")) |
104 |
|
105 |
script = ( "/sbin/syslogd &\n" |
106 |
"sleep 2\n" |
107 |
"/sbin/e-smith/signal-event post-install\n" ) |
108 |
s = Script(script, interp="/bin/sh", inChroot=1) |
109 |
log("%s", s) |
110 |
s.run(rootPath, serial) |
111 |
win.pop() |
112 |
|
113 |
log("Running kickstart %%post script(s)") |
114 |
for script in self.postScripts: |
115 |
script.run(rootPath, serial) |
116 |
log("All kickstart %%post script(s) have been run") |
117 |
|
118 |
def doRootPw(self, id, args): |
119 |
(args, extra) = isys.getopt(args, '', [ 'iscrypted' ]) |
120 |
|
121 |
isCrypted = 0 |
122 |
for n in args: |
123 |
(str, arg) = n |
124 |
if (str == '--iscrypted'): |
125 |
isCrypted = 1 |
126 |
|
127 |
if len(extra) != 1: |
128 |
raise KickstartValueError, "a single argument is expected to rootPw" |
129 |
|
130 |
self.setRootPassword(id, extra[0], isCrypted = isCrypted) |
131 |
self.skipSteps.append("accounts") |
132 |
|
133 |
def doFirewall(self, id, args): |
134 |
(args, extra) = isys.getopt(args, '', |
135 |
[ 'dhcp', 'ssh', 'telnet', 'smtp', 'http', 'ftp', 'enabled', |
136 |
'enable', 'port=', 'high', 'medium', 'disabled', 'disable', |
137 |
'trust=' ]) |
138 |
|
139 |
enable = -1 |
140 |
trusts = [] |
141 |
ports = [] |
142 |
|
143 |
for n in args: |
144 |
(str, arg) = n |
145 |
if str == '--ssh': |
146 |
ports.append("22:tcp") |
147 |
elif str == '--telnet': |
148 |
ports.append("23:tcp") |
149 |
elif str == '--smtp': |
150 |
ports.append("25:tcp") |
151 |
elif str == '--http': |
152 |
ports.extend(["80:tcp", "443:tcp"]) |
153 |
elif str == '--ftp': |
154 |
ports.append("21:tcp") |
155 |
elif str == '--high' or str == '--medium': |
156 |
log("used deprecated firewall option: %s" %(str[2:],)) |
157 |
enable = 1 |
158 |
elif str == '--enabled' or str == "--enable": |
159 |
enable = 1 |
160 |
elif str == '--disabled' or str == "--disable": |
161 |
enable = 0 |
162 |
elif str == '--trust': |
163 |
trusts.append(arg) |
164 |
elif str == '--port': |
165 |
theports = arg.split(",") |
166 |
for p in theports: |
167 |
p = p.strip() |
168 |
if p.find(":") == -1: |
169 |
p = "%s:tcp" %(p,) |
170 |
ports.append(p) |
171 |
|
172 |
self.setFirewall(id, enable, trusts, ports) |
173 |
|
174 |
def doSELinux(self, id, args): |
175 |
(args, extra) = isys.getopt(args, '', |
176 |
[ 'disabled', 'enforcing', |
177 |
'permissive' ] ) |
178 |
|
179 |
sel = 2 |
180 |
|
181 |
for n in args: |
182 |
(str, arg) = n |
183 |
if str == "--disabled": |
184 |
sel = 0 |
185 |
elif str == "--permissive": |
186 |
sel = 1 |
187 |
elif str == "--enforcing": |
188 |
sel = 2 |
189 |
|
190 |
self.setSELinux(id, sel) |
191 |
|
192 |
def doZFCP(self, id, args): |
193 |
(args, extra) = isys.getopt(args, '', |
194 |
["devnum", "scsiid", "wwpn", "scsilun", |
195 |
"fcplun"]) |
196 |
|
197 |
devnum = None |
198 |
scsiid = None |
199 |
wwpn = None |
200 |
scsilun = None |
201 |
fcplun = None |
202 |
|
203 |
for n in args: |
204 |
(str, arg) = n |
205 |
if str == "--devnum": |
206 |
devnum = id.zfcp.sanitizeDeviceInput(arg) |
207 |
elif str == "--scsid": |
208 |
scsiid = id.zfcp.sanitizeHexInput(arg) |
209 |
elif str == "--wwpn": |
210 |
wwpn = id.zfcp.sanitizeHexInput(arg) |
211 |
elif str == "--scsilun": |
212 |
scsilun = id.zfcp.sanitizeHexInput(arg) |
213 |
elif str == "--fcplun": |
214 |
fcplun = id.zfcp.sanitizeFCPLInput(arg) |
215 |
|
216 |
if id.zfcp.checkValidDevice(devnum) == -1: |
217 |
raise KickstartValueError, "Invalid devnum specified" |
218 |
if id.zfcp.checkValidID(scsiid) == -1: |
219 |
raise KickstartValueError, "Invalid scsiid specified" |
220 |
if id.zfcp.checkValid64BitHex(wwpn) == -1: |
221 |
raise KickstartValueError, "Invalid wwpn specified" |
222 |
if id.zfcp.checkValidID(scsilun) == -1: |
223 |
raise KickstartValueError, "Invalid scsilun specified" |
224 |
if id.zfcp.checkValid64BitHex(fcplun) == -1: |
225 |
raise KickstartValueError, "Invalid fcplun specified" |
226 |
|
227 |
if ((devnum is None) or (scsiid is None) or (wwpn is None) |
228 |
or (scsilun is None) or (fcplun is None)): |
229 |
raise KickstartError, "ZFCP config must specify all of devnum, scsiid, wwpn, scsilun, and fcplun" |
230 |
|
231 |
self.setZFCP(id, devnum, scsiid, wwpn, scsilun, fcplun) |
232 |
self.skipSteps.append("zfcpconfig") |
233 |
|
234 |
def doAuthconfig(self, id, args): |
235 |
(args, extra) = isys.getopt(args, '', |
236 |
[ 'useshadow', 'enableshadow', |
237 |
'enablemd5', |
238 |
'enablenis', 'nisdomain=', 'nisserver=', |
239 |
'enableldap', 'enableldapauth', 'ldapserver=', 'ldapbasedn=', |
240 |
'enableldaptls', |
241 |
'enablekrb5', 'krb5realm=', 'krb5kdc=', 'krb5adminserver=', |
242 |
'enablehesiod', 'hesiodlhs=', 'hesiodrhs=', |
243 |
'enablesmbauth', 'smbservers=', 'smbworkgroup=', |
244 |
'enablecache']) |
245 |
|
246 |
useShadow = 0 |
247 |
|
248 |
useMd5 = 0 |
249 |
|
250 |
useNis = 0 |
251 |
nisServer = "" |
252 |
nisDomain = "" |
253 |
nisBroadcast = 0 |
254 |
|
255 |
useLdap = 0 |
256 |
useLdapauth = 0 |
257 |
useLdaptls = 0 |
258 |
ldapServer = "" |
259 |
ldapBasedn = "" |
260 |
|
261 |
useKrb5 = 0 |
262 |
krb5Realm = "" |
263 |
krb5Kdc = "" |
264 |
krb5Admin = "" |
265 |
|
266 |
useHesiod = 0 |
267 |
hesiodLhs = "" |
268 |
hesiodRhs = "" |
269 |
|
270 |
useSamba = 0 |
271 |
smbServers = "" |
272 |
smbWorkgroup = "" |
273 |
|
274 |
enableCache = 0 |
275 |
|
276 |
for n in args: |
277 |
(str, arg) = n |
278 |
if (str == '--enablenis'): |
279 |
useNis = 1 |
280 |
elif (str == '--useshadow') or (str == '--enableshadow'): |
281 |
useShadow = 1 |
282 |
elif (str == '--enablemd5'): |
283 |
useMd5 = 1 |
284 |
elif (str == '--nisserver'): |
285 |
nisServer = arg |
286 |
elif (str == '--nisdomain'): |
287 |
nisDomain = arg |
288 |
elif (str == '--enableldap'): |
289 |
useLdap = 1 |
290 |
elif (str == '--enableldapauth'): |
291 |
useLdapauth = 1 |
292 |
elif (str == '--ldapserver'): |
293 |
ldapServer = arg |
294 |
elif (str == '--ldapbasedn'): |
295 |
ldapBasedn = arg |
296 |
elif (str == '--enableldaptls'): |
297 |
useLdaptls = 1 |
298 |
elif (str == '--enablekrb5'): |
299 |
useKrb5 = 1 |
300 |
elif (str == '--krb5realm'): |
301 |
krb5Realm = arg |
302 |
elif (str == '--krb5kdc'): |
303 |
krb5Kdc = arg |
304 |
elif (str == '--krb5adminserver'): |
305 |
krb5Admin = arg |
306 |
elif (str == '--enablehesiod'): |
307 |
useHesiod = 1 |
308 |
elif (str == '--hesiodlhs'): |
309 |
hesiodLhs = arg |
310 |
elif (str == '--hesiodrhs'): |
311 |
hesiodRhs = arg |
312 |
elif (str == '--enablesmbauth'): |
313 |
useSamba = 1 |
314 |
elif (str == '--smbservers'): |
315 |
smbServers = arg |
316 |
elif (str == '--smbworkgroup'): |
317 |
smbWorkgroup = arg |
318 |
elif (str == '--enablecache'): |
319 |
enableCache = 1 |
320 |
|
321 |
|
322 |
if useNis and not nisServer: nisBroadcast = 1 |
323 |
|
324 |
self.setAuthentication(id, useShadow, useMd5, |
325 |
useNis, nisDomain, nisBroadcast, nisServer, |
326 |
useLdap, useLdapauth, ldapServer, |
327 |
ldapBasedn, useLdaptls, |
328 |
useKrb5, krb5Realm, krb5Kdc, krb5Admin, |
329 |
useHesiod, hesiodLhs, hesiodRhs, |
330 |
useSamba, smbServers, smbWorkgroup, |
331 |
enableCache) |
332 |
|
333 |
self.skipSteps.append("authentication") |
334 |
|
335 |
def doBootloader (self, id, args, useLilo = 0): |
336 |
(args, extra) = isys.getopt(args, '', |
337 |
[ 'append=', 'location=', 'useLilo', 'lba32', |
338 |
'password=', 'md5pass=', 'linear', 'nolinear', |
339 |
'upgrade', 'driveorder=']) |
340 |
|
341 |
validLocations = [ "mbr", "partition", "none", "boot" ] |
342 |
appendLine = "" |
343 |
location = "mbr" |
344 |
password = None |
345 |
md5pass = None |
346 |
forceLBA = 0 |
347 |
linear = 1 |
348 |
upgrade = 0 |
349 |
driveorder = [] |
350 |
|
351 |
for n in args: |
352 |
(str, arg) = n |
353 |
if str == '--append': |
354 |
appendLine = arg |
355 |
elif str == '--location': |
356 |
location = arg |
357 |
elif str == '--useLilo': |
358 |
# log("used deprecated option --useLilo, ignoring") |
359 |
useLilo = 1 |
360 |
elif str == '--linear': |
361 |
linear = 1 |
362 |
elif str == '--nolinear': |
363 |
linear = 0 |
364 |
elif str == '--lba32': |
365 |
forceLBA = 1 |
366 |
elif str == '--password': |
367 |
password = arg |
368 |
elif str == '--md5pass': |
369 |
md5pass = arg |
370 |
elif str == '--upgrade': |
371 |
upgrade = 1 |
372 |
elif str == '--driveorder': |
373 |
driveorder = string.split(arg, ',') |
374 |
|
375 |
if location not in validLocations: |
376 |
raise KickstartValueError, "mbr, partition, or none expected for bootloader command" |
377 |
if location == "none": |
378 |
location = None |
379 |
elif location == "partition": |
380 |
location = "boot" |
381 |
|
382 |
if upgrade and not id.upgrade.get(): |
383 |
raise KickstartError, "Selected upgrade mode for bootloader but not doing an upgrade" |
384 |
|
385 |
if upgrade: |
386 |
id.bootloader.kickstart = 1 |
387 |
id.bootloader.doUpgradeOnly = 1 |
388 |
|
389 |
if location is None: |
390 |
self.skipSteps.append("bootloadersetup") |
391 |
self.skipSteps.append("instbootloader") |
392 |
else: |
393 |
self.showSteps.append("bootloadersetup") |
394 |
self.setBootloader(id, useLilo, location, linear, forceLBA, |
395 |
password, md5pass, appendLine, driveorder) |
396 |
|
397 |
self.skipSteps.append("upgbootloader") |
398 |
self.skipSteps.append("bootloader") |
399 |
self.skipSteps.append("bootloaderadvanced") |
400 |
|
401 |
def doLilo (self, id, args): |
402 |
self.doBootloader(id, args, useLilo = 1) |
403 |
|
404 |
def doFirstboot(self, id, args): |
405 |
(args, extra) = isys.getopt(args, '', |
406 |
['reconfig', 'enable', 'enabled', |
407 |
'disable', 'disabled']) |
408 |
|
409 |
fb = FIRSTBOOT_SKIP |
410 |
|
411 |
for n in args: |
412 |
(str, arg) = n |
413 |
if str == '--reconfig': |
414 |
fb = FIRSTBOOT_RECONFIG |
415 |
elif str == '--enable' or str == "--enabled": |
416 |
fb = FIRSTBOOT_DEFAULT |
417 |
elif str == '--disable' or str == "--disabled": |
418 |
fb = FIRSTBOOT_SKIP |
419 |
|
420 |
id.firstboot = fb |
421 |
|
422 |
|
423 |
def doLiloCheck (self, id, args): |
424 |
drives = isys.hardDriveDict ().keys() |
425 |
drives.sort(isys.compareDrives) |
426 |
device = drives[0] |
427 |
isys.makeDevInode(device, '/tmp/' + device) |
428 |
fd = os.open('/tmp/' + device, os.O_RDONLY) |
429 |
os.unlink('/tmp/' + device) |
430 |
block = os.read(fd, 512) |
431 |
os.close(fd) |
432 |
if block[6:10] == "LILO": |
433 |
sys.exit(0) |
434 |
|
435 |
def doTimezone(self, id, args): |
436 |
(args, extra) = isys.getopt(args, '', |
437 |
[ 'utc' ]) |
438 |
|
439 |
isUtc = 0 |
440 |
|
441 |
for n in args: |
442 |
(str, arg) = n |
443 |
if str == '--utc': |
444 |
isUtc = 1 |
445 |
|
446 |
self.setTimezoneInfo(id, extra[0], asUtc = isUtc) |
447 |
|
448 |
self.skipSteps.append("timezone") |
449 |
|
450 |
|
451 |
def doXconfig(self, id, args): |
452 |
(args, extra) = isys.getopt(args, '', |
453 |
[ 'server=', 'card=', 'videoram=', |
454 |
'monitor=', 'hsync=', 'vsync=', |
455 |
'resolution=', 'depth=', |
456 |
'startxonboot', 'noprobe', 'defaultdesktop=' ]) |
457 |
|
458 |
if extra: |
459 |
raise KickstartValueError, "unexpected arguments to xconfig command" |
460 |
|
461 |
server = None |
462 |
card = None |
463 |
videoRam = None |
464 |
monitor = None |
465 |
hsync = None |
466 |
vsync = None |
467 |
resolution = None |
468 |
depth = None |
469 |
noProbe = 0 |
470 |
startX = 0 |
471 |
defaultdesktop = "" |
472 |
|
473 |
for n in args: |
474 |
(str, arg) = n |
475 |
if (str == "--noprobe"): |
476 |
noProbe = 1 |
477 |
elif (str == "--server"): |
478 |
server = arg |
479 |
elif (str == "--card"): |
480 |
card = arg |
481 |
elif (str == "--videoram"): |
482 |
videoRam = arg |
483 |
elif (str == "--monitor"): |
484 |
monitor = arg |
485 |
elif (str == "--hsync"): |
486 |
hsync = arg |
487 |
elif (str == "--vsync"): |
488 |
vsync = arg |
489 |
elif (str == "--resolution"): |
490 |
resolution = arg |
491 |
elif (str == "--depth"): |
492 |
depth = string.atoi(arg) |
493 |
elif (str == "--startxonboot"): |
494 |
startX = 1 |
495 |
elif (str == "--defaultdesktop"): |
496 |
defaultdesktop = arg |
497 |
|
498 |
self.configureX(id, server, card, videoRam, monitor, hsync, vsync, |
499 |
resolution, depth, noProbe, startX) |
500 |
self.setDesktop(id, defaultdesktop) |
501 |
|
502 |
self.skipSteps.append("videocard") |
503 |
self.skipSteps.append("monitor") |
504 |
self.skipSteps.append("xcustom") |
505 |
self.skipSteps.append("handleX11pkgs") |
506 |
self.skipSteps.append("checkmonitorok") |
507 |
self.skipSteps.append("setsanex") |
508 |
|
509 |
def doMonitor(self, id, args): |
510 |
(args, extra) = isys.getopt(args, '', |
511 |
[ 'monitor=', 'hsync=', 'vsync=' ]) |
512 |
|
513 |
if extra: |
514 |
raise KickstartValueError, "unexpected arguments to monitor command" |
515 |
|
516 |
monitor = None |
517 |
hsync = None |
518 |
vsync = None |
519 |
|
520 |
for n in args: |
521 |
(str, arg) = n |
522 |
if (str == "--monitor"): |
523 |
monitor = arg |
524 |
elif (str == "--hsync"): |
525 |
hsync = arg |
526 |
elif (str == "--vsync"): |
527 |
vsync = arg |
528 |
|
529 |
self.skipSteps.append("monitor") |
530 |
self.skipSteps.append("checkmonitorok") |
531 |
|
532 |
self.setMonitor(id, hsync = hsync, vsync = vsync, |
533 |
monitorName = monitor) |
534 |
|
535 |
def doUpgrade(self, id, args): |
536 |
self.installType = "upgrade" |
537 |
id.upgrade.set(1) |
538 |
|
539 |
def doNetwork(self, id, args): |
540 |
# nodns is only used by the loader |
541 |
(args, extra) = isys.getopt(args, '', |
542 |
[ 'bootproto=', 'ip=', 'netmask=', 'gateway=', 'nameserver=', |
543 |
'nodns', 'device=', 'hostname=', 'ethtool=', 'onboot=', |
544 |
'dhcpclass=', 'essid=', 'wepkey=', 'notksdevice']) |
545 |
bootProto = "dhcp" |
546 |
ip = None |
547 |
netmask = "" |
548 |
gateway = "" |
549 |
nameserver = "" |
550 |
hostname = "" |
551 |
ethtool = "" |
552 |
essid = "" |
553 |
wepkey = "" |
554 |
onboot = 1 |
555 |
device = None |
556 |
dhcpclass = None |
557 |
for n in args: |
558 |
(str, arg) = n |
559 |
if str == "--bootproto": |
560 |
bootProto = arg |
561 |
elif str == "--ip": |
562 |
ip = arg |
563 |
elif str == "--netmask": |
564 |
netmask = arg |
565 |
elif str == "--gateway": |
566 |
gateway = arg |
567 |
elif str == "--nameserver": |
568 |
nameserver = arg |
569 |
elif str == "--device": |
570 |
device = arg |
571 |
elif str == "--hostname": |
572 |
hostname = arg |
573 |
elif str== "--ethtool": |
574 |
ethtool = arg |
575 |
elif str == "--essid": |
576 |
essid = arg |
577 |
elif str == "--wepkey": |
578 |
wepkey = arg |
579 |
elif str== "--onboot": |
580 |
if arg == 'no': |
581 |
onboot = 0 |
582 |
else: |
583 |
onboot = 1 |
584 |
elif str == "--class": |
585 |
dhcpclass = arg |
586 |
|
587 |
self.setNetwork(id, bootProto, ip, netmask, ethtool, device=device, onboot=onboot, dhcpclass=dhcpclass, essid=essid, wepkey=wepkey) |
588 |
if hostname != "": |
589 |
self.setHostname(id, hostname, override = 1) |
590 |
if nameserver != "": |
591 |
self.setNameserver(id, nameserver) |
592 |
if gateway != "": |
593 |
self.setGateway(id, gateway) |
594 |
|
595 |
def doLang(self, id, args): |
596 |
self.setLanguage(id, args[0]) |
597 |
self.skipSteps.append("language") |
598 |
|
599 |
def doLangSupport (self, id, args): |
600 |
(args, extra) = isys.getopt(args, '', [ 'default=' ]) |
601 |
deflang = "en_US.UTF-8" |
602 |
if args: |
603 |
deflang = args[0][1] |
604 |
else: |
605 |
# if they specified no default we default to en_US if |
606 |
# they installed support for more than one lang, otherwise |
607 |
# we default to the one language they specified support for |
608 |
if extra is None: |
609 |
deflang = "en_US.UTF-8" |
610 |
elif len(extra) >= 1: |
611 |
deflang = extra[0] |
612 |
else: |
613 |
deflang = "en_US.UTF-8" |
614 |
|
615 |
self.setLanguageDefault (id, deflang) |
616 |
self.setLanguageSupport(id, extra) |
617 |
|
618 |
self.skipSteps.append("languagesupport") |
619 |
|
620 |
def doKeyboard(self, id, args): |
621 |
self.setKeyboard(id, args[0]) |
622 |
id.keyboard.beenset = 1 |
623 |
self.skipSteps.append("keyboard") |
624 |
|
625 |
def doZeroMbr(self, id, args): |
626 |
self.setZeroMbr(id, 1) |
627 |
|
628 |
def doMouse(self, id, args): |
629 |
#Don't do anything with mice anymore |
630 |
return |
631 |
|
632 |
## (args, extra) = isys.getopt(args, '', [ 'device=', 'emulthree' ]) |
633 |
## mouseType = "none" |
634 |
## device = None |
635 |
## emulThree = 0 |
636 |
|
637 |
## for n in args: |
638 |
## (str, arg) = n |
639 |
## if str == "--device": |
640 |
## device = arg |
641 |
## elif str == "--emulthree": |
642 |
## emulThree = 1 |
643 |
|
644 |
## if extra: |
645 |
## mouseType = extra[0] |
646 |
|
647 |
## if mouseType != "none": |
648 |
## self.setMouse(id, mouseType, device, emulThree) |
649 |
|
650 |
## self.skipSteps.append("mouse") |
651 |
|
652 |
def doReboot(self, id, args): |
653 |
self.skipSteps.append("complete") |
654 |
|
655 |
def doSkipX(self, id, args): |
656 |
self.skipSteps.append("checkmonitorok") |
657 |
self.skipSteps.append("setsanex") |
658 |
self.skipSteps.append("videocard") |
659 |
self.skipSteps.append("monitor") |
660 |
self.skipSteps.append("xcustom") |
661 |
self.skipSteps.append("handleX11pkgs") |
662 |
self.skipSteps.append("writexconfig") |
663 |
if id.xsetup is not None: |
664 |
id.xsetup.skipx = 1 |
665 |
|
666 |
def doInteractive(self, id, args): |
667 |
self.interactive = 1 |
668 |
|
669 |
def doAutoStep(self, id, args): |
670 |
flags.autostep = 1 |
671 |
flags.autoscreenshot = 0 |
672 |
|
673 |
(xargs, xtra) = isys.getopt(args, '', ['autoscreenshot']) |
674 |
for n in xargs: |
675 |
(str, arg) = n |
676 |
if str == "--autoscreenshot": |
677 |
flags.autoscreenshot = 1 |
678 |
|
679 |
|
680 |
# read the kickstart config... if parsePre is set, only parse |
681 |
# the %pre, otherwise ignore the %pre. assume we're starting in where |
682 |
def readKickstart(self, id, file, parsePre = 0, where = "commands"): |
683 |
handlers = { |
684 |
"auth" : self.doAuthconfig , |
685 |
"authconfig" : self.doAuthconfig , |
686 |
"autopart" : self.doAutoPart , |
687 |
"cdrom" : None , |
688 |
"clearpart" : self.doClearPart , |
689 |
"ignoredisk" : self.doIgnoreDisk , |
690 |
"device" : None , |
691 |
"deviceprobe" : None , |
692 |
"driverdisk" : None , |
693 |
"firewall" : self.doFirewall , |
694 |
"selinux" : self.doSELinux , |
695 |
"harddrive" : None , |
696 |
"install" : None , |
697 |
"keyboard" : self.doKeyboard , |
698 |
"lang" : self.doLang , |
699 |
"langsupport" : self.doLangSupport , |
700 |
"lilo" : self.doLilo , |
701 |
"bootloader" : self.doBootloader , |
702 |
"lilocheck" : self.doLiloCheck , |
703 |
"mouse" : self.doMouse , |
704 |
"network" : self.doNetwork , |
705 |
"nfs" : None , |
706 |
"part" : self.definePartition , |
707 |
"partition" : self.definePartition , |
708 |
"raid" : self.defineRaid , |
709 |
"volgroup" : self.defineVolumeGroup, |
710 |
"logvol" : self.defineLogicalVolume, |
711 |
"reboot" : self.doReboot , |
712 |
"poweroff" : self.doReboot , |
713 |
"halt" : self.doReboot , |
714 |
"shutdown" : self.doReboot , |
715 |
"rootpw" : self.doRootPw , |
716 |
"skipx" : self.doSkipX , |
717 |
"text" : None , |
718 |
"graphical" : None , |
719 |
"cmdline" : None , |
720 |
"timezone" : self.doTimezone , |
721 |
"url" : None , |
722 |
"upgrade" : self.doUpgrade , |
723 |
"xconfig" : self.doXconfig , |
724 |
"monitor" : self.doMonitor , |
725 |
"xdisplay" : None , |
726 |
"zerombr" : self.doZeroMbr , |
727 |
"interactive" : self.doInteractive , |
728 |
"autostep" : self.doAutoStep , |
729 |
"firstboot" : self.doFirstboot , |
730 |
"vnc" : None , |
731 |
} |
732 |
|
733 |
packages = [] |
734 |
groups = [] |
735 |
excludedPackages = [] |
736 |
|
737 |
script = "" |
738 |
scriptInterp = "/bin/sh" |
739 |
scriptLog = None |
740 |
if where == "pre" or where == "traceback": |
741 |
scriptChroot = 0 |
742 |
else: |
743 |
scriptChroot = 1 |
744 |
|
745 |
for n in open(file).readlines(): |
746 |
args = isys.parseArgv(n) |
747 |
|
748 |
# don't eliminate white space or comments from scripts |
749 |
if where not in ["pre", "post", "traceback"]: |
750 |
if not args or args[0][0] == '#': continue |
751 |
|
752 |
if args and (args[0] in ["%pre", "%post", "%traceback"]): |
753 |
if ((where =="pre" and parsePre) or |
754 |
(where in ["post", "traceback"] and not parsePre)): |
755 |
s = Script(script, scriptInterp, scriptChroot, scriptLog) |
756 |
if where == "pre": |
757 |
self.preScripts.append(s) |
758 |
elif where == "post": |
759 |
self.postScripts.append(s) |
760 |
else: |
761 |
self.tracebackScripts.append(s) |
762 |
|
763 |
where = args[0][1:] |
764 |
args = isys.parseArgv(n) |
765 |
|
766 |
script = "" |
767 |
scriptInterp = "/bin/sh" |
768 |
scriptLog = None |
769 |
if where == "pre" or where == "traceback": |
770 |
scriptChroot = 0 |
771 |
else: |
772 |
scriptChroot = 1 |
773 |
|
774 |
argList = [ 'interpreter=', "log=", "logfile=" ] |
775 |
if where == "post": |
776 |
argList.append('nochroot') |
777 |
|
778 |
(args, extra) = isys.getopt(args, '', argList) |
779 |
for n in args: |
780 |
(str, arg) = n |
781 |
|
782 |
if str == "--nochroot": |
783 |
scriptChroot = 0 |
784 |
elif str == "--interpreter": |
785 |
scriptInterp = arg |
786 |
elif str == "--log" or str == "--logfile": |
787 |
scriptLog = arg |
788 |
|
789 |
elif args and args[0] == "%include" and not parsePre: |
790 |
if len(args) < 2: |
791 |
raise KickstartError, "Invalid %include line" |
792 |
else: |
793 |
# read in the included file and set our where appropriately |
794 |
where = self.readKickstart(id, args[1], where = where) |
795 |
elif args and args[0] == "%packages": |
796 |
if ((where =="pre" and parsePre) or |
797 |
(where in ["post", "traceback"] and not parsePre)): |
798 |
s = Script(script, scriptInterp, scriptChroot, scriptLog) |
799 |
if where == "pre": |
800 |
self.preScripts.append(s) |
801 |
elif where == "post": |
802 |
self.postScripts.append(s) |
803 |
else: |
804 |
self.tracebackScripts.append(s) |
805 |
|
806 |
# if we're parsing the %pre, we don't need to continue |
807 |
if parsePre: |
808 |
continue |
809 |
|
810 |
if len(args) > 1: |
811 |
for arg in args[1:]: |
812 |
if arg == "--resolvedeps": |
813 |
id.handleDeps = RESOLVE_DEPS |
814 |
elif arg == "--ignoredeps": |
815 |
id.handleDeps = IGNORE_DEPS |
816 |
elif arg == "--excludedocs": |
817 |
id.excludeDocs = 1 |
818 |
elif arg == "--ignoremissing": |
819 |
self.handleMissing = KS_MISSING_IGNORE |
820 |
elif arg == "--nobase": |
821 |
self.addBase = 0 |
822 |
|
823 |
where = "packages" |
824 |
self.skipSteps.append("package-selection") |
825 |
else: |
826 |
# if we're parsing the %pre and not in the pre, continue |
827 |
if parsePre and where != "pre": |
828 |
continue |
829 |
elif where == "packages": |
830 |
#Scan for comments in package list...drop off |
831 |
#everything after "#" mark |
832 |
try: |
833 |
ind = string.index(n, "#") |
834 |
n = n[:ind] |
835 |
except: |
836 |
#No "#" found in line |
837 |
pass |
838 |
|
839 |
if n[0] == '@': |
840 |
n = n[1:] |
841 |
n = string.strip (n) |
842 |
groups.append(n) |
843 |
elif n[0] == '-': |
844 |
n = n[1:] |
845 |
n = string.strip(n) |
846 |
excludedPackages.append(n) |
847 |
else: |
848 |
n = string.strip (n) |
849 |
packages.append(n) |
850 |
elif where == "commands": |
851 |
if handlers.has_key(args[0]): |
852 |
if handlers[args[0]] is not None: |
853 |
handlers[args[0]](id, args[1:]) |
854 |
else: |
855 |
# unrecognized command |
856 |
raise KickstartError, "Unrecognized ks command: %s\nOn the line: %s" % (args[0], n) |
857 |
elif where in ["pre", "post", "traceback"]: |
858 |
script = script + n |
859 |
else: |
860 |
raise KickstartError, "I'm lost in kickstart" |
861 |
|
862 |
self.groupList.extend(groups) |
863 |
self.packageList.extend(packages) |
864 |
self.excludedList.extend(excludedPackages) |
865 |
|
866 |
# test to see if they specified to clear partitions and also |
867 |
# tried to --onpart on a logical partition |
868 |
# |
869 |
# XXX |
870 |
# |
871 |
#if iutil.getArch() == 'i386' and self.fstab: |
872 |
#clear = self.getClearParts() |
873 |
#if clear == FSEDIT_CLEAR_LINUX or clear == FSEDIT_CLEAR_ALL: |
874 |
#for (mntpoint, (dev, fstype, reformat)) in self.fstab: |
875 |
#if int(dev[-1:]) > 4: |
876 |
#raise RuntimeError, "Clearpart and --onpart on non-primary partition %s not allowed" % dev |
877 |
|
878 |
if ((where =="pre" and parsePre) or |
879 |
(where in ["post", "traceback"] and not parsePre)): |
880 |
s = Script(script, scriptInterp, scriptChroot, scriptLog) |
881 |
if where == "pre": |
882 |
self.preScripts.append(s) |
883 |
elif where == "post": |
884 |
self.postScripts.append(s) |
885 |
else: |
886 |
self.tracebackScripts.append(s) |
887 |
|
888 |
return where |
889 |
|
890 |
def doClearPart(self, id, args): |
891 |
type = CLEARPART_TYPE_NONE |
892 |
drives = None |
893 |
initAll = 0 |
894 |
|
895 |
(args, extra) = isys.getopt(args, '', [ 'linux', 'all', 'drives=', |
896 |
'initlabel', 'none']) |
897 |
|
898 |
for n in args: |
899 |
(str, arg) = n |
900 |
if str == '--linux': |
901 |
type = CLEARPART_TYPE_LINUX |
902 |
elif str == '--all': |
903 |
type = CLEARPART_TYPE_ALL |
904 |
elif str == '--drives': |
905 |
drives = string.split(arg, ',') |
906 |
elif str == '--initlabel': |
907 |
initAll = 1 |
908 |
elif str == '--none': |
909 |
type = CLEARPART_TYPE_NONE |
910 |
|
911 |
self.setClearParts(id, type, drives, initAll = initAll) |
912 |
|
913 |
# this adds a partition to the autopartition list replacing anything |
914 |
# else with this mountpoint so that you can use autopart and override / |
915 |
def addPartRequest(self, partitions, request): |
916 |
if not request.mountpoint: |
917 |
partitions.autoPartitionRequests.append(request) |
918 |
return |
919 |
|
920 |
for req in partitions.autoPartitionRequests: |
921 |
if req.mountpoint and req.mountpoint == request.mountpoint: |
922 |
partitions.autoPartitionRequests.remove(req) |
923 |
break |
924 |
partitions.autoPartitionRequests.append(request) |
925 |
|
926 |
def doAutoPart(self, id, args): |
927 |
# sets up default autopartitioning. use clearpart separately |
928 |
# if you want it |
929 |
self.setDefaultPartitioning(id, doClear = 0) |
930 |
|
931 |
id.partitions.isKickstart = 1 |
932 |
|
933 |
self.skipSteps.append("partition") |
934 |
self.skipSteps.append("partitionmethod") |
935 |
self.skipSteps.append("partitionmethodsetup") |
936 |
self.skipSteps.append("fdisk") |
937 |
self.skipSteps.append("autopartition") |
938 |
self.skipSteps.append("zfcpconfig") |
939 |
|
940 |
def defineLogicalVolume(self, id, args): |
941 |
(args, extra) = isys.getopt(args, '', [ 'vgname=', |
942 |
'size=', |
943 |
'name=', |
944 |
'fstype=', |
945 |
'percent=', |
946 |
'maxsize=', |
947 |
'grow', |
948 |
'recommended', |
949 |
'noformat', |
950 |
'useexisting']) |
951 |
|
952 |
mountpoint = None |
953 |
vgname = None |
954 |
size = None |
955 |
name = None |
956 |
fstype = None |
957 |
percent = None |
958 |
grow = 0 |
959 |
maxSizeMB = 0 |
960 |
format = 1 |
961 |
recommended = None |
962 |
preexist = 0 |
963 |
|
964 |
for n in args: |
965 |
(str, arg) = n |
966 |
if str == '--vgname': |
967 |
vgname = arg |
968 |
elif str == '--size': |
969 |
size = int(arg) |
970 |
elif str == '--name': |
971 |
name = arg |
972 |
elif str == '--fstype': |
973 |
fstype = arg |
974 |
elif str == '--percent': |
975 |
percent = int(arg) |
976 |
elif str == '--maxsize': |
977 |
maxSizeMB = int(arg) |
978 |
elif str == '--grow': |
979 |
grow = 1 |
980 |
elif str == '--recommended': |
981 |
recommended = 1 |
982 |
elif str == "--noformat": |
983 |
format = 0 |
984 |
preexist = 1 |
985 |
elif str == "--useexisting": |
986 |
preexist = 1 |
987 |
|
988 |
if extra[0] == 'swap': |
989 |
filesystem = fileSystemTypeGet('swap') |
990 |
mountpoint = None |
991 |
if recommended: |
992 |
(size, maxSizeMB) = iutil.swapSuggestion() |
993 |
grow = 1 |
994 |
else: |
995 |
if fstype: |
996 |
filesystem = fileSystemTypeGet(fstype) |
997 |
else: |
998 |
filesystem = fileSystemTypeGetDefault() |
999 |
|
1000 |
mountpoint = extra[0] |
1001 |
|
1002 |
# sanity check mountpoint |
1003 |
if mountpoint is not None and mountpoint[0] != '/': |
1004 |
raise KickstartError, "The mount point \"%s\" is not valid." % (mountpoint,) |
1005 |
|
1006 |
if not vgname: |
1007 |
raise KickstartError, "Must specify the volume group for the logical volume to be in" |
1008 |
if not size and not percent and not preexist: |
1009 |
raise KickstartError, "Must specify the size of a logical volume" |
1010 |
if percent and percent <= 0 or percent > 100: |
1011 |
raise KickstartValueError, "Logical Volume percentage must be between 0 and 100 percent" |
1012 |
|
1013 |
if not name: |
1014 |
raise KickstartError, "Must specify a logical volume name" |
1015 |
|
1016 |
vgid = self.ksVGMapping[vgname] |
1017 |
for areq in id.partitions.autoPartitionRequests: |
1018 |
if areq.type == REQUEST_LV: |
1019 |
if areq.volumeGroup == vgid and areq.logicalVolumeName == name: |
1020 |
raise KickstartValueError, "Logical volume name %s already used in volume group %s" % (name,vgname) |
1021 |
|
1022 |
if not self.ksVGMapping.has_key(vgname): |
1023 |
raise KickstartValueError, "Logical volume specifies a non-existent volume group" |
1024 |
|
1025 |
request = partRequests.LogicalVolumeRequestSpec(filesystem, |
1026 |
format = format, |
1027 |
mountpoint = mountpoint, |
1028 |
size = size, |
1029 |
percent = percent, |
1030 |
volgroup = vgid, |
1031 |
lvname = name, |
1032 |
grow = grow, |
1033 |
maxSizeMB=maxSizeMB, |
1034 |
preexist = preexist) |
1035 |
self.addPartRequest(id.partitions, request) |
1036 |
|
1037 |
|
1038 |
def defineVolumeGroup(self, id, args): |
1039 |
(args, extra) = isys.getopt(args, '', ['noformat','useexisting', |
1040 |
'pesize=']) |
1041 |
|
1042 |
preexist = 0 |
1043 |
format = 1 |
1044 |
pesize = 32768 |
1045 |
|
1046 |
vgname = extra[0] |
1047 |
|
1048 |
for n in args: |
1049 |
(str, arg) = n |
1050 |
if str == '--noformat' or str == '--useexisting': |
1051 |
preexist = 1 |
1052 |
format = 0 |
1053 |
elif str == "--pesize": |
1054 |
pesize = int(arg) |
1055 |
|
1056 |
pvs = [] |
1057 |
# get the unique ids of each of the physical volumes |
1058 |
for pv in extra[1:]: |
1059 |
if pv not in self.ksPVMapping.keys(): |
1060 |
raise KickstartError, "Tried to use an undefined partition in Volume Group specification" |
1061 |
pvs.append(self.ksPVMapping[pv]) |
1062 |
|
1063 |
if len(pvs) == 0 and not preexist: |
1064 |
raise KickstartError, "Volume group defined without any physical volumes" |
1065 |
|
1066 |
if pesize not in lvm.getPossiblePhysicalExtents(floor=1024): |
1067 |
raise KickstartError, "Volume group specified invalid pesize: %d" %(pesize,) |
1068 |
|
1069 |
# get a sort of hackish id |
1070 |
uniqueID = self.ksID |
1071 |
self.ksVGMapping[extra[0]] = uniqueID |
1072 |
self.ksID = self.ksID + 1 |
1073 |
|
1074 |
request = partRequests.VolumeGroupRequestSpec(vgname = vgname, |
1075 |
physvols = pvs, |
1076 |
preexist = preexist, |
1077 |
format = format, |
1078 |
pesize = pesize) |
1079 |
request.uniqueID = uniqueID |
1080 |
self.addPartRequest(id.partitions, request) |
1081 |
|
1082 |
def defineRaid(self, id, args): |
1083 |
(args, extra) = isys.getopt(args, '', [ 'level=', 'device=', |
1084 |
'spares=', 'fstype=', |
1085 |
'noformat', 'useexisting'] ) |
1086 |
|
1087 |
level = None |
1088 |
raidDev = None |
1089 |
spares = 0 |
1090 |
fstype = None |
1091 |
format = 1 |
1092 |
uniqueID = None |
1093 |
preexist = 0 |
1094 |
|
1095 |
for n in args: |
1096 |
(str, arg) = n |
1097 |
if str == '--level': |
1098 |
level = arg |
1099 |
elif str == "--device": |
1100 |
raidDev = arg |
1101 |
if raidDev[0:2] == "md": |
1102 |
raidDev = raidDev[2:] |
1103 |
raidDev = int(raidDev) |
1104 |
elif str == "--spares": |
1105 |
spares = int(arg) |
1106 |
elif str == "--noformat": |
1107 |
format = 0 |
1108 |
preexist = 1 |
1109 |
elif str == "--useexisting": |
1110 |
preexist = 1 |
1111 |
elif str == "--fstype": |
1112 |
fstype = arg |
1113 |
|
1114 |
if extra[0] == 'swap': |
1115 |
filesystem = fileSystemTypeGet('swap') |
1116 |
mountpoint = None |
1117 |
elif extra[0].startswith("pv."): |
1118 |
filesystem = fileSystemTypeGet("physical volume (LVM)") |
1119 |
mountpoint = None |
1120 |
|
1121 |
if self.ksPVMapping.has_key(extra[0]): |
1122 |
raise KickstartError, "Defined PV partition %s multiple times" % (extra[0],) |
1123 |
|
1124 |
# get a sort of hackish id |
1125 |
uniqueID = self.ksID |
1126 |
self.ksPVMapping[extra[0]] = uniqueID |
1127 |
self.ksID = self.ksID + 1 |
1128 |
else: |
1129 |
if fstype: |
1130 |
filesystem = fileSystemTypeGet(fstype) |
1131 |
else: |
1132 |
filesystem = fileSystemTypeGetDefault() |
1133 |
|
1134 |
mountpoint = extra[0] |
1135 |
|
1136 |
# sanity check mountpoint |
1137 |
if mountpoint is not None and mountpoint[0] != '/': |
1138 |
raise KickstartError, "The mount point \"%s\" is not valid." % (mountpoint,) |
1139 |
|
1140 |
raidmems = [] |
1141 |
# get the unique ids of each of the raid members |
1142 |
for member in extra[1:]: |
1143 |
if member not in self.ksRaidMapping.keys(): |
1144 |
raise KickstartError, "Tried to use an undefined partition in RAID specification" |
1145 |
if member in self.ksUsedMembers: |
1146 |
raise KickstartError, "Tried to use the RAID member %s in two or more RAID specifications" % (member,) |
1147 |
|
1148 |
raidmems.append(self.ksRaidMapping[member]) |
1149 |
self.ksUsedMembers.append(member) |
1150 |
|
1151 |
# XXX this shouldn't have to happen =\ |
1152 |
if raid.isRaid0(level): |
1153 |
level = "RAID0" |
1154 |
elif raid.isRaid1(level): |
1155 |
level = "RAID1" |
1156 |
elif raid.isRaid5(level): |
1157 |
level = "RAID5" |
1158 |
elif raid.isRaid6(level): |
1159 |
level = "RAID6" |
1160 |
|
1161 |
if not level and preexist == 0: |
1162 |
raise KickstartValueError, "RAID Partition defined without RAID level" |
1163 |
if len(raidmems) == 0 and preexist == 0: |
1164 |
raise KickstartValueError, "RAID Partition defined without any RAID members" |
1165 |
|
1166 |
request = partRequests.RaidRequestSpec(filesystem, |
1167 |
mountpoint = mountpoint, |
1168 |
raidmembers = raidmems, |
1169 |
raidlevel = level, |
1170 |
raidspares = spares, |
1171 |
format = format, |
1172 |
raidminor = raidDev, |
1173 |
preexist = preexist) |
1174 |
|
1175 |
if uniqueID: |
1176 |
request.uniqueID = uniqueID |
1177 |
if preexist and raidDev is not None: |
1178 |
request.device = "md%s" %(raidDev,) |
1179 |
|
1180 |
self.addPartRequest(id.partitions, request) |
1181 |
|
1182 |
|
1183 |
def definePartition(self, id, args): |
1184 |
# we set up partition requests (whee!) |
1185 |
size = None |
1186 |
grow = None |
1187 |
maxSize = None |
1188 |
disk = None |
1189 |
onPart = None |
1190 |
fsopts = None |
1191 |
type = None |
1192 |
primOnly = None |
1193 |
format = 1 |
1194 |
fstype = None |
1195 |
mountpoint = None |
1196 |
uniqueID = None |
1197 |
start = None |
1198 |
end = None |
1199 |
badblocks = None |
1200 |
recommended = None |
1201 |
|
1202 |
(args, extra) = isys.getopt(args, '', [ 'size=', 'maxsize=', |
1203 |
'grow', 'onpart=', 'ondisk=', |
1204 |
'bytes-per-inode=', 'usepart=', |
1205 |
'type=', 'fstype=', 'asprimary', |
1206 |
'noformat', 'start=', 'end=', |
1207 |
'badblocks', 'recommended', |
1208 |
'ondrive=', 'onbiosdisk=' ]) |
1209 |
|
1210 |
for n in args: |
1211 |
(str, arg) = n |
1212 |
if str == '--size': |
1213 |
size = int(arg) |
1214 |
elif str == '--maxsize': |
1215 |
maxSize = int(arg) |
1216 |
elif str == '--grow': |
1217 |
grow = 1 |
1218 |
elif str == '--onpart' or str == '--usepart': |
1219 |
onPart = arg |
1220 |
elif str == '--ondisk' or str == '--ondrive': |
1221 |
disk = arg |
1222 |
elif str == '--onbiosdisk': |
1223 |
disk = isys.doGetBiosDisk(arg) |
1224 |
if disk is None: |
1225 |
raise KickstartValueError, "Specified BIOS disk %s cannot be determined" %(arg,) |
1226 |
elif str == '--bytes-per-inode': |
1227 |
fsopts = ['-i', arg] |
1228 |
# XXX this doesn't do anything right now |
1229 |
elif str == '--type': |
1230 |
type = int(arg) |
1231 |
elif str == "--active": |
1232 |
active = 1 |
1233 |
elif str == "--asprimary": |
1234 |
primOnly = 1 |
1235 |
elif str == "--noformat": |
1236 |
format = 0 |
1237 |
elif str == "--fstype": |
1238 |
fstype = arg |
1239 |
elif str == "--start": |
1240 |
start = int(arg) |
1241 |
elif str == "--end": |
1242 |
end = int(arg) |
1243 |
elif str == "--badblocks": |
1244 |
# no longer support badblocks checking |
1245 |
log("WARNING: --badblocks specified but is no longer supported") |
1246 |
elif str == "--recommended": |
1247 |
recommended = 1 |
1248 |
|
1249 |
if len(extra) != 1: |
1250 |
raise KickstartValueError, "partition command requires one anonymous argument" |
1251 |
|
1252 |
if extra[0] == 'swap': |
1253 |
filesystem = fileSystemTypeGet('swap') |
1254 |
mountpoint = None |
1255 |
if recommended: |
1256 |
(size, maxSize) = iutil.swapSuggestion() |
1257 |
grow = 1 |
1258 |
# if people want to specify no mountpoint for some reason, let them |
1259 |
# this is really needed for pSeries boot partitions :( |
1260 |
elif extra[0] == 'None': |
1261 |
mountpoint = None |
1262 |
if fstype: |
1263 |
filesystem = fileSystemTypeGet(fstype) |
1264 |
else: |
1265 |
filesystem = fileSystemTypeGetDefault() |
1266 |
elif extra[0] == 'prepboot': |
1267 |
filesystem = fileSystemTypeGet("PPC PReP Boot") |
1268 |
mountpoint = None |
1269 |
elif extra[0].startswith("raid."): |
1270 |
filesystem = fileSystemTypeGet("software RAID") |
1271 |
|
1272 |
if self.ksRaidMapping.has_key(extra[0]): |
1273 |
raise KickstartError, "Defined RAID partition %s multiple times" % (extra[0],) |
1274 |
|
1275 |
# get a sort of hackish id |
1276 |
uniqueID = self.ksID |
1277 |
self.ksRaidMapping[extra[0]] = uniqueID |
1278 |
self.ksID = self.ksID + 1 |
1279 |
elif extra[0].startswith("pv."): |
1280 |
filesystem = fileSystemTypeGet("physical volume (LVM)") |
1281 |
|
1282 |
if self.ksPVMapping.has_key(extra[0]): |
1283 |
raise KickstartError, "Defined PV partition %s multiple times" % (extra[0],) |
1284 |
|
1285 |
# get a sort of hackish id |
1286 |
uniqueID = self.ksID |
1287 |
self.ksPVMapping[extra[0]] = uniqueID |
1288 |
self.ksID = self.ksID + 1 |
1289 |
# XXX should we let people not do this for some reason? |
1290 |
elif extra[0] == "/boot/efi": |
1291 |
filesystem = fileSystemTypeGet("vfat") |
1292 |
mountpoint = extra[0] |
1293 |
else: |
1294 |
if fstype: |
1295 |
filesystem = fileSystemTypeGet(fstype) |
1296 |
mountpoint = extra[0] |
1297 |
else: |
1298 |
filesystem = fileSystemTypeGetDefault() |
1299 |
mountpoint = extra[0] |
1300 |
|
1301 |
if (size is None) and (not start and not end) and (not onPart): |
1302 |
raise KickstartValueError, "partition command requires a size specification" |
1303 |
if start and not disk: |
1304 |
raise KickstartValueError, "partition command with start cylinder requires a drive specification" |
1305 |
if disk and disk not in isys.hardDriveDict().keys(): |
1306 |
raise KickstartValueError, "specified disk %s in partition command which does not exist" %(disk,) |
1307 |
|
1308 |
# XXX bytes per inode is the only per fs option at the moment |
1309 |
# and we can assume that it works like this since it only works |
1310 |
# with ext[23] |
1311 |
if fsopts: |
1312 |
filesystem.extraFormatArgs.extend(fsopts) |
1313 |
|
1314 |
request = partRequests.PartitionSpec(filesystem, |
1315 |
mountpoint = mountpoint, |
1316 |
format = 1) |
1317 |
|
1318 |
if size is not None: |
1319 |
request.size = size |
1320 |
if start: |
1321 |
request.start = start |
1322 |
if end: |
1323 |
request.end = end |
1324 |
if grow: |
1325 |
request.grow = 1 |
1326 |
if maxSize: |
1327 |
request.maxSizeMB = maxSize |
1328 |
if disk: |
1329 |
request.drive = [ disk ] |
1330 |
if primOnly: |
1331 |
request.primary = 1 |
1332 |
if not format: |
1333 |
request.format = 0 |
1334 |
if uniqueID: |
1335 |
request.uniqueID = uniqueID |
1336 |
if badblocks: |
1337 |
request.badblocks = badblocks |
1338 |
if onPart: |
1339 |
# strip spurious /dev |
1340 |
if onPart.startswith("/dev/"): |
1341 |
onPart = onPart[5:] |
1342 |
request.device = onPart |
1343 |
for areq in id.partitions.autoPartitionRequests: |
1344 |
if areq.device is not None and areq.device == onPart: |
1345 |
raise KickstartValueError, "Partition %s already used" %(onPart,) |
1346 |
|
1347 |
self.addPartRequest(id.partitions, request) |
1348 |
id.partitions.isKickstart = 1 |
1349 |
|
1350 |
self.skipSteps.append("partition") |
1351 |
self.skipSteps.append("partitionmethod") |
1352 |
self.skipSteps.append("partitionmethodsetup") |
1353 |
self.skipSteps.append("fdisk") |
1354 |
self.skipSteps.append("autopartition") |
1355 |
self.skipSteps.append("zfcpconfig") |
1356 |
|
1357 |
def doIgnoreDisk(self, id, args): |
1358 |
# add disks to ignore list |
1359 |
drives = [] |
1360 |
(args, extra) = isys.getopt(args, '', [ 'drives=' ]) |
1361 |
|
1362 |
for n in args: |
1363 |
(str, arg) = n |
1364 |
if str == '--drives': |
1365 |
drives = string.split(arg, ',') |
1366 |
|
1367 |
self.setIgnoredDisks(id, drives) |
1368 |
|
1369 |
def setSteps(self, dispatch): |
1370 |
if self.installType == "upgrade": |
1371 |
from upgradeclass import InstallClass |
1372 |
theUpgradeclass = InstallClass(0) |
1373 |
theUpgradeclass.setSteps(dispatch) |
1374 |
|
1375 |
# we have no way to specify migrating yet |
1376 |
dispatch.skipStep("upgrademigfind") |
1377 |
dispatch.skipStep("upgrademigratefs") |
1378 |
dispatch.skipStep("upgradecontinue") |
1379 |
dispatch.skipStep("findinstall", permanent = 1) |
1380 |
dispatch.skipStep("language") |
1381 |
dispatch.skipStep("keyboard") |
1382 |
# dispatch.skipStep("mouse") |
1383 |
dispatch.skipStep("welcome") |
1384 |
dispatch.skipStep("betanag") |
1385 |
dispatch.skipStep("installtype") |
1386 |
else: |
1387 |
BaseInstallClass.setSteps(self, dispatch) |
1388 |
dispatch.skipStep("findrootparts") |
1389 |
|
1390 |
if self.interactive or flags.autostep: |
1391 |
dispatch.skipStep("installtype") |
1392 |
dispatch.skipStep("partitionmethod") |
1393 |
dispatch.skipStep("partitionmethodsetup") |
1394 |
dispatch.skipStep("fdisk") |
1395 |
dispatch.skipStep("autopartition") |
1396 |
dispatch.skipStep("bootdisk") |
1397 |
|
1398 |
# because these steps depend on the monitor being probed |
1399 |
# properly, and will stop you if you have an unprobed monitor, |
1400 |
# we should skip them for autostep |
1401 |
if flags.autostep: |
1402 |
dispatch.skipStep("checkmonitorok") |
1403 |
dispatch.skipStep("monitor") |
1404 |
return |
1405 |
|
1406 |
dispatch.skipStep("bootdisk") |
1407 |
dispatch.skipStep("welcome") |
1408 |
dispatch.skipStep("betanag") |
1409 |
dispatch.skipStep("confirminstall") |
1410 |
dispatch.skipStep("confirmupgrade") |
1411 |
dispatch.skipStep("network") |
1412 |
dispatch.skipStep("installtype") |
1413 |
|
1414 |
# skipping firewall by default, disabled by default |
1415 |
dispatch.skipStep("firewall") |
1416 |
|
1417 |
for n in self.skipSteps: |
1418 |
dispatch.skipStep(n) |
1419 |
for n in self.showSteps: |
1420 |
dispatch.skipStep(n, skip = 0) |
1421 |
|
1422 |
def setInstallData(self, id, intf = None): |
1423 |
BaseInstallClass.setInstallData(self, id) |
1424 |
|
1425 |
self.setEarlySwapOn(1) |
1426 |
self.postScripts = [] |
1427 |
self.preScripts = [] |
1428 |
self.tracebackScripts = [] |
1429 |
|
1430 |
self.installType = "install" |
1431 |
self.id = id |
1432 |
self.id.firstboot = FIRSTBOOT_SKIP |
1433 |
|
1434 |
# parse the %pre |
1435 |
try: |
1436 |
self.readKickstart(id, self.file, parsePre = 1) |
1437 |
except KickstartError, e: |
1438 |
raise KickstartError, e |
1439 |
|
1440 |
log("Running kickstart %%pre script(s)") |
1441 |
for script in self.preScripts: |
1442 |
script.run("/", self.serial) |
1443 |
log("All kickstart %%pre script(s) have been run") |
1444 |
|
1445 |
# now read the kickstart file for real |
1446 |
try: |
1447 |
self.readKickstart(id, self.file) |
1448 |
except KickstartError, e: |
1449 |
log("Exception parsing ks.cfg: %s" %(e,)) |
1450 |
if intf is None: |
1451 |
raise KickstartError, e |
1452 |
else: |
1453 |
intf.kickstartErrorWindow(e.__str__()) |
1454 |
|
1455 |
def runTracebackScripts(self): |
1456 |
log("Running kickstart %%traceback script(s)") |
1457 |
for script in self.tracebackScripts: |
1458 |
script.run("/", self.serial) |
1459 |
|
1460 |
# Note that this assumes setGroupSelection() is called before |
1461 |
# setPackageSelection() |
1462 |
def setPackageSelection(self, hdlist, intf): |
1463 |
for n in self.packageList: |
1464 |
|
1465 |
# allow arch:name syntax |
1466 |
if n.find(".") != -1: |
1467 |
fields = n.split(".") |
1468 |
name = string.join(fields[:-1], ".") |
1469 |
arch = fields[-1] |
1470 |
found = 0 |
1471 |
if hdlist.pkgnames.has_key(name): |
1472 |
pkgs = hdlist.pkgnames[name] |
1473 |
for (nevra, parch) in pkgs: |
1474 |
if parch == arch: |
1475 |
hdlist.pkgs[nevra].select() |
1476 |
found = 1 |
1477 |
continue |
1478 |
if found: |
1479 |
continue |
1480 |
|
1481 |
if hdlist.has_key(n): |
1482 |
hdlist[n].select() |
1483 |
continue |
1484 |
|
1485 |
if self.handleMissing == KS_MISSING_IGNORE: |
1486 |
log("package %s doesn't exist, ignoring" %(n,)) |
1487 |
continue |
1488 |
|
1489 |
|
1490 |
rc = intf.messageWindow(_("Missing Package"), |
1491 |
_("You have specified that the " |
1492 |
"package '%s' should be installed. " |
1493 |
"This package does not exist. " |
1494 |
"Would you like to continue or " |
1495 |
"abort your installation?") %(n,), |
1496 |
type="custom", |
1497 |
custom_buttons=[_("_Abort"), |
1498 |
_("_Continue")]) |
1499 |
if rc == 0: |
1500 |
sys.exit(1) |
1501 |
else: |
1502 |
pass |
1503 |
|
1504 |
|
1505 |
def setGroupSelection(self, grpset, intf): |
1506 |
grpset.unselectAll() |
1507 |
|
1508 |
if self.addBase: |
1509 |
grpset.selectGroup("base") |
1510 |
for n in self.groupList: |
1511 |
try: |
1512 |
grpset.selectGroup(n) |
1513 |
except KeyError: |
1514 |
if self.handleMissing == KS_MISSING_IGNORE: |
1515 |
log("group %s doesn't exist, ignoring" %(n,)) |
1516 |
else: |
1517 |
rc = intf.messageWindow(_("Missing Group"), |
1518 |
_("You have specified that the " |
1519 |
"group '%s' should be installed. " |
1520 |
"This group does not exist. " |
1521 |
"Would you like to continue or " |
1522 |
"abort your installation?") |
1523 |
%(n,), |
1524 |
type="custom", |
1525 |
custom_buttons=[_("_Abort"), |
1526 |
_("_Continue")]) |
1527 |
if rc == 0: |
1528 |
sys.exit(1) |
1529 |
else: |
1530 |
pass |
1531 |
|
1532 |
for n in self.excludedList: |
1533 |
# allow arch:name syntax |
1534 |
if n.find(".") != -1: |
1535 |
fields = n.split(".") |
1536 |
name = string.join(fields[:-1], ".") |
1537 |
arch = fields[-1] |
1538 |
if grpset.hdrlist.pkgnames.has_key(name): |
1539 |
pkgs = grpset.hdrlist.pkgnames[name] |
1540 |
for (nevra, parch) in pkgs: |
1541 |
if parch == arch: |
1542 |
grpset.hdrlist.pkgs[nevra].unselect(isManual = 1) |
1543 |
continue |
1544 |
|
1545 |
if grpset.hdrlist.has_key(n): |
1546 |
grpset.hdrlist[n].unselect(isManual = 1) |
1547 |
else: |
1548 |
log("%s does not exist, can't exclude" %(n,)) |
1549 |
|
1550 |
|
1551 |
def __init__(self, file, serial): |
1552 |
self.serial = serial |
1553 |
self.file = file |
1554 |
self.skipSteps = [] |
1555 |
self.showSteps = [] |
1556 |
self.interactive = 0 |
1557 |
self.addBase = 1 |
1558 |
self.packageList = [] |
1559 |
self.groupList = [] |
1560 |
self.excludedList = [] |
1561 |
self.ksRaidMapping = {} |
1562 |
self.ksUsedMembers = [] |
1563 |
self.ksPVMapping = {} |
1564 |
self.ksVGMapping = {} |
1565 |
# XXX hack to give us a starting point for RAID, LVM, etc unique IDs. |
1566 |
self.ksID = 100000 |
1567 |
|
1568 |
# how to handle missing packages |
1569 |
self.handleMissing = KS_MISSING_PROMPT |
1570 |
|
1571 |
BaseInstallClass.__init__(self, 0) |
1572 |
|
1573 |
def Kickstart(file, serial): |
1574 |
|
1575 |
f = open(file, "r") |
1576 |
lines = f.readlines() |
1577 |
f.close() |
1578 |
|
1579 |
passedLines = [] |
1580 |
while lines: |
1581 |
l = lines[0] |
1582 |
lines = lines[1:] |
1583 |
if l == "%installclass\n": |
1584 |
break |
1585 |
passedLines.append(l) |
1586 |
|
1587 |
if lines: |
1588 |
newKsFile = file + ".new" |
1589 |
f = open(newKsFile, "w") |
1590 |
f.writelines(passedLines) |
1591 |
f.close() |
1592 |
|
1593 |
f = open('/tmp/ksclass.py', "w") |
1594 |
f.writelines(lines) |
1595 |
f.close() |
1596 |
|
1597 |
oldPath = sys.path |
1598 |
sys.path.append('/tmp') |
1599 |
|
1600 |
from ksclass import CustomKickstart |
1601 |
os.unlink("/tmp/ksclass.py") |
1602 |
|
1603 |
ksClass = CustomKickstart(newKsFile, serial) |
1604 |
os.unlink(newKsFile) |
1605 |
else: |
1606 |
ksClass = KickstartBase(file, serial) |
1607 |
|
1608 |
return ksClass |
1609 |
|
1610 |
|
1611 |
# see if any vnc parameters are specified in the kickstart file |
1612 |
def parseKickstartVNC(ksfile): |
1613 |
try: |
1614 |
f = open(ksfile, "r") |
1615 |
except: |
1616 |
raise KSAppendException("Unable to open ks file %s" % (ksfile,)) |
1617 |
|
1618 |
lines = f.readlines() |
1619 |
f.close() |
1620 |
|
1621 |
usevnc = 0 |
1622 |
vnchost = None |
1623 |
vncport = None |
1624 |
vncpasswd = None |
1625 |
for l in lines: |
1626 |
args = isys.parseArgv(l) |
1627 |
|
1628 |
if args: |
1629 |
if args[0] in ("%pre", "%post", "%traceback", "%packages"): |
1630 |
break |
1631 |
|
1632 |
if args[0] != 'vnc': |
1633 |
continue |
1634 |
else: |
1635 |
continue |
1636 |
|
1637 |
idx = 1 |
1638 |
while idx < len(args): |
1639 |
if args[idx] == "--password": |
1640 |
try: |
1641 |
vncpasswd = args[idx+1] |
1642 |
except: |
1643 |
raise KickstartError, "Missing argument to vnc --password option" |
1644 |
idx += 2 |
1645 |
elif args[idx] == "--connect": |
1646 |
try: |
1647 |
connectspec = args[idx+1] |
1648 |
except: |
1649 |
raise KickstartError, "Missing argument to vnc --connect option" |
1650 |
cargs = string.split(connectspec, ":") |
1651 |
vnchost = cargs[0] |
1652 |
if len(cargs) > 1: |
1653 |
if len(cargs[1]) > 0: |
1654 |
vncport = cargs[1] |
1655 |
|
1656 |
idx += 2 |
1657 |
else: |
1658 |
raise KickstartError, "Unknown vnc option %s" % (args[idx],) |
1659 |
|
1660 |
usevnc = 1 |
1661 |
break |
1662 |
|
1663 |
return (usevnc, vncpasswd, vnchost, vncport) |
1664 |
|
1665 |
# |
1666 |
# look through ksfile and if it contains a line: |
1667 |
# |
1668 |
# %ksappend <url> |
1669 |
# |
1670 |
# pull <url> down and append to /tmp/ks.cfg. This is run before we actually |
1671 |
# parse the complete kickstart file. |
1672 |
# |
1673 |
# Main use is to have the ks.cfg you send to the loader by minimal, and then |
1674 |
# use %ksappend to pull via https anything private (like passwords, etc) in |
1675 |
# the second stage. |
1676 |
# |
1677 |
def pullRemainingKickstartConfig(ksfile): |
1678 |
try: |
1679 |
f = open(ksfile, "r") |
1680 |
except: |
1681 |
raise KSAppendException("Unable to open ks file %s" % (ksfile,)) |
1682 |
|
1683 |
lines = f.readlines() |
1684 |
f.close() |
1685 |
|
1686 |
url = None |
1687 |
for l in lines: |
1688 |
ll = l.strip() |
1689 |
if string.find(ll, "%ksappend") == -1: |
1690 |
continue |
1691 |
|
1692 |
try: |
1693 |
(xxx, ksurl) = string.split(ll, ' ') |
1694 |
except: |
1695 |
raise KSAppendException("Illegal url for %%ksappend - %s" % (ll,)) |
1696 |
|
1697 |
log("Attempting to pull second part of ks.cfg from url %s" % (ksurl,)) |
1698 |
|
1699 |
try: |
1700 |
url = urllib2.urlopen(ksurl) |
1701 |
except urllib2.HTTPError, e: |
1702 |
raise KSAppendException("IOError: %s:%s" % (e.code, e.msg)) |
1703 |
except urllib2.URLError, e: |
1704 |
raise KSAppendException("IOError: -1:%s" % (e.reason,)) |
1705 |
else: |
1706 |
# sanity check result - sometimes FTP doesnt |
1707 |
# catch a file is missing |
1708 |
try: |
1709 |
clen = url.info()['content-length'] |
1710 |
except Exception, e: |
1711 |
clen = 0 |
1712 |
|
1713 |
if clen < 1: |
1714 |
raise KSAppendException("IOError: -1:File not found") |
1715 |
|
1716 |
break |
1717 |
|
1718 |
# if we got something then rewrite /tmp/ks.cfg with new information |
1719 |
if url is not None: |
1720 |
os.rename("/tmp/ks.cfg", "/tmp/ks.cfg-part1") |
1721 |
|
1722 |
# insert contents of original /tmp/ks.cfg w/o %ksappend line |
1723 |
f = open("/tmp/ks.cfg", 'w+') |
1724 |
for l in lines: |
1725 |
ll = l.strip() |
1726 |
if string.find(ll, "%ksappend") != -1: |
1727 |
continue |
1728 |
f.write(l) |
1729 |
|
1730 |
# now write part we just grabbed |
1731 |
f.write(url.read()) |
1732 |
f.close() |
1733 |
|
1734 |
# close up url and we're done |
1735 |
url.close() |
1736 |
|
1737 |
return None |
1738 |
|