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