Timezone setting change
[platform/upstream/mic.git] / mic / kickstart / __init__.py
1 #!/usr/bin/python -tt
2 #
3 # Copyright (c) 2007 Red Hat, Inc.
4 # Copyright (c) 2009, 2010, 2011 Intel, Inc.
5 #
6 # This program is free software; you can redistribute it and/or modify it
7 # under the terms of the GNU General Public License as published by the Free
8 # Software Foundation; version 2 of the License
9 #
10 # This program is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 # or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13 # for more details.
14 #
15 # You should have received a copy of the GNU General Public License along
16 # with this program; if not, write to the Free Software Foundation, Inc., 59
17 # Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 import os, sys, re
20 import shutil
21 import subprocess
22 import string
23 import collections
24
25 import pykickstart.sections as kssections
26 import pykickstart.commands as kscommands
27 import pykickstart.constants as ksconstants
28 import pykickstart.errors as kserrors
29 import pykickstart.parser as ksparser
30 import pykickstart.version as ksversion
31 from pykickstart.handlers.control import commandMap
32 from pykickstart.handlers.control import dataMap
33
34 from mic import msger
35 from mic.utils import errors, misc, runner, fs_related as fs
36 from custom_commands import desktop, micrepo, micboot, partition, installerfw
37 from mic.utils.safeurl import SafeURL
38
39
40 AUTH_URL_PTN = r"(?P<scheme>.*)://(?P<username>.*)(:?P<password>.*)?@(?P<url>.*)"
41
42
43 class PrepackageSection(kssections.Section):
44     sectionOpen = "%prepackages"
45
46     def handleLine(self, line):
47         if not self.handler:
48             return
49
50         (h, s, t) = line.partition('#')
51         line = h.rstrip()
52
53         self.handler.prepackages.add([line])
54
55     def handleHeader(self, lineno, args):
56         kssections.Section.handleHeader(self, lineno, args)
57
58 class AttachmentSection(kssections.Section):
59     sectionOpen = "%attachment"
60
61     def handleLine(self, line):
62         if not self.handler:
63             return
64
65         (h, s, t) = line.partition('#')
66         line = h.rstrip()
67
68         self.handler.attachment.add([line])
69
70     def handleHeader(self, lineno, args):
71         kssections.Section.handleHeader(self, lineno, args)
72
73 def apply_wrapper(func):
74     def wrapper(*kargs, **kwargs):
75         try:
76             func(*kargs, **kwargs)
77         except (OSError, IOError, errors.KsError), err:
78             cfgcls = kargs[0].__class__.__name__
79             if msger.ask("Failed to apply %s, skip and continue?" % cfgcls):
80                 msger.warning("%s" % err)
81                 pass
82             else:
83                 # just throw out the exception
84                 raise
85     return wrapper
86
87 def read_kickstart(path):
88     """Parse a kickstart file and return a KickstartParser instance.
89
90     This is a simple utility function which takes a path to a kickstart file,
91     parses it and returns a pykickstart KickstartParser instance which can
92     be then passed to an ImageCreator constructor.
93
94     If an error occurs, a CreatorError exception is thrown.
95     """
96
97     #version = ksversion.makeVersion()
98     #ks = ksparser.KickstartParser(version)
99
100     using_version = ksversion.DEVEL
101     commandMap[using_version]["desktop"] = desktop.Mic_Desktop
102     commandMap[using_version]["repo"] = micrepo.Mic_Repo
103     commandMap[using_version]["bootloader"] = micboot.Mic_Bootloader
104     commandMap[using_version]["part"] = partition.Mic_Partition
105     commandMap[using_version]["partition"] = partition.Mic_Partition
106     commandMap[using_version]["installerfw_plugins"] = installerfw.Mic_installerfw
107     dataMap[using_version]["RepoData"] = micrepo.Mic_RepoData
108     dataMap[using_version]["PartData"] = partition.Mic_PartData
109     superclass = ksversion.returnClassForVersion(version=using_version)
110
111     class KSHandlers(superclass):
112         def __init__(self):
113             superclass.__init__(self, mapping=commandMap[using_version])
114             self.prepackages = ksparser.Packages()
115             self.attachment = ksparser.Packages()
116
117     ks = ksparser.KickstartParser(KSHandlers(), errorsAreFatal=False)
118     ks.registerSection(PrepackageSection(ks.handler))
119     ks.registerSection(AttachmentSection(ks.handler))
120
121     try:
122         ks.readKickstart(path)
123     except (kserrors.KickstartParseError, kserrors.KickstartError), err:
124         if msger.ask("Errors occured on kickstart file, skip and continue?"):
125             msger.warning("%s" % err)
126             pass
127         else:
128             raise errors.KsError("%s" % err)
129
130     return ks
131
132 class KickstartConfig(object):
133     """A base class for applying kickstart configurations to a system."""
134     def __init__(self, instroot):
135         self.instroot = instroot
136
137     def path(self, subpath):
138         return self.instroot + subpath
139
140     def _check_sysconfig(self):
141         if not os.path.exists(self.path("/etc/sysconfig")):
142             fs.makedirs(self.path("/etc/sysconfig"))
143
144     def chroot(self):
145         os.chroot(self.instroot)
146         os.chdir("/")
147
148     def call(self, args):
149         if not os.path.exists("%s/%s" %(self.instroot, args[0])):
150             raise errors.KsError("Can't find %s in chroot" % args[0])
151         subprocess.call(args, preexec_fn = self.chroot)
152
153     def apply(self):
154         pass
155
156 class LanguageConfig(KickstartConfig):
157     """A class to apply a kickstart language configuration to a system."""
158     @apply_wrapper
159     def apply(self, kslang):
160         self._check_sysconfig()
161         if kslang.lang:
162             f = open(self.path("/etc/sysconfig/i18n"), "w+")
163             f.write("LANG=\"" + kslang.lang + "\"\n")
164             f.close()
165
166             f = open(self.path("/etc/locale.conf"), "w+")
167             f.write("LANG=\"" + kslang.lang + "\"\n")
168             f.close()
169
170             #cp ks lang setting to other file, then can access the file in %post section
171             fs.makedirs(self.path("/etc/config"))
172             f = open(self.path("/etc/config/mic_language"), "w+")
173             f.write("LANG=\"" + kslang.lang + "\"\n")
174             f.close()
175
176 class KeyboardConfig(KickstartConfig):
177     """A class to apply a kickstart keyboard configuration to a system."""
178     @apply_wrapper
179     def apply(self, kskeyboard):
180         #
181         # FIXME:
182         #   should this impact the X keyboard config too?
183         #   or do we want to make X be able to do this mapping?
184         #
185         #k = rhpl.keyboard.Keyboard()
186         #if kskeyboard.keyboard:
187         #   k.set(kskeyboard.keyboard)
188         #k.write(self.instroot)
189         pass
190
191 class TimezoneConfig(KickstartConfig):
192     """A class to apply a kickstart timezone configuration to a system."""
193     @apply_wrapper
194     def apply(self, kstimezone):
195         self._check_sysconfig()
196         tz = kstimezone.timezone or "America/New_York"
197         utc = str(kstimezone.isUtc)
198
199         f = open(self.path("/etc/sysconfig/clock"), "w+")
200         f.write("ZONE=\"" + tz + "\"\n")
201         f.write("UTC=" + utc + "\n")
202         f.close()
203         if not os.path.exists("/opt/etc"):
204             fs.makedirs("/opt/etc")
205         tz_source = "/usr/share/zoneinfo/%s" % (tz)
206         tz_midst = "/opt/etc/localtime"
207         tz_dest = "/etc/localtime"
208         try:
209             lncmd = fs.find_binary_inchroot('ln', self.instroot)
210             if lncmd:
211                 self.call([lncmd, "-s", tz_source, tz_midst])
212                 self.call([lncmd, "-s", tz_midst, tz_dest])
213             else:
214                 lncmd = fs.find_binary_path('ln')
215                 subprocess.call([lncmd, "-s",
216                                  self.path(tz_source),
217                                  self.path(tz_midst)])
218                 subprocess.call([lncmd, "-s",
219                                  self.path(tz_midst),
220                                  self.path(tz_dest)])
221         except (IOError, OSError), (errno, msg):
222             raise errors.KsError("Timezone setting error: %s" % msg)
223
224 class AuthConfig(KickstartConfig):
225     """A class to apply a kickstart authconfig configuration to a system."""
226     @apply_wrapper
227     def apply(self, ksauthconfig):
228         auth = ksauthconfig.authconfig or "--useshadow --enablemd5"
229         args = ["/usr/share/authconfig/authconfig.py", "--update", "--nostart"]
230         self.call(args + auth.split())
231
232 class FirewallConfig(KickstartConfig):
233     """A class to apply a kickstart firewall configuration to a system."""
234     @apply_wrapper
235     def apply(self, ksfirewall):
236         #
237         # FIXME: should handle the rest of the options
238         #
239         if not os.path.exists(self.path("/usr/sbin/lokkit")):
240             return
241         if ksfirewall.enabled:
242             status = "--enabled"
243         else:
244             status = "--disabled"
245
246         self.call(["/usr/sbin/lokkit",
247                    "-f", "--quiet", "--nostart", status])
248
249 class RootPasswordConfig(KickstartConfig):
250     """A class to apply a kickstart root password configuration to a system."""
251     def unset(self):
252         self.call(["/usr/bin/passwd", "-d", "root"])
253
254     def set_encrypted(self, password):
255         self.call(["/usr/sbin/usermod", "-p", password, "root"])
256
257     def set_unencrypted(self, password):
258         for p in ("/bin/echo", "/usr/sbin/chpasswd"):
259             if not os.path.exists("%s/%s" %(self.instroot, p)):
260                 raise errors.KsError("Unable to set unencrypted password due "
261                                      "to lack of %s" % p)
262
263         p1 = subprocess.Popen(["/bin/echo", "root:%s" %password],
264                               stdout = subprocess.PIPE,
265                               preexec_fn = self.chroot)
266         p2 = subprocess.Popen(["/usr/sbin/chpasswd", "-m"],
267                               stdin = p1.stdout,
268                               stdout = subprocess.PIPE,
269                               preexec_fn = self.chroot)
270         p2.communicate()
271
272     @apply_wrapper
273     def apply(self, ksrootpw):
274         if ksrootpw.isCrypted:
275             self.set_encrypted(ksrootpw.password)
276         elif ksrootpw.password != "":
277             self.set_unencrypted(ksrootpw.password)
278         else:
279             self.unset()
280
281 class UserConfig(KickstartConfig):
282     def set_empty_passwd(self, user):
283         self.call(["/usr/bin/passwd", "-d", user])
284
285     def set_encrypted_passwd(self, user, password):
286         self.call(["/usr/sbin/usermod", "-p", "%s" % password, user])
287
288     def set_unencrypted_passwd(self, user, password):
289         for p in ("/bin/echo", "/usr/sbin/chpasswd"):
290             if not os.path.exists("%s/%s" %(self.instroot, p)):
291                 raise errors.KsError("Unable to set unencrypted password due "
292                                      "to lack of %s" % p)
293
294         p1 = subprocess.Popen(["/bin/echo", "%s:%s" %(user, password)],
295                               stdout = subprocess.PIPE,
296                               preexec_fn = self.chroot)
297         p2 = subprocess.Popen(["/usr/sbin/chpasswd", "-m"],
298                               stdin = p1.stdout,
299                               stdout = subprocess.PIPE,
300                               preexec_fn = self.chroot)
301         p2.communicate()
302
303     def addUser(self, userconfig):
304         args = [ "/usr/sbin/useradd" ]
305         if userconfig.groups:
306             args += [ "--groups", string.join(userconfig.groups, ",") ]
307         if userconfig.name:
308             args += [ "-m"]
309             args += [ "-d", "/home/%s" % userconfig.name  ]
310             args.append(userconfig.name)
311             try:
312                 dev_null = os.open("/dev/null", os.O_WRONLY)
313                 msger.debug('adding user with %s' % args)
314                 subprocess.call(args,
315                                  stdout = dev_null,
316                                  stderr = dev_null,
317                                  preexec_fn = self.chroot)
318                 os.close(dev_null)
319             except:
320                 msger.warning('Cannot add user using "useradd"')
321
322             if userconfig.password not in (None, ""):
323                 if userconfig.isCrypted:
324                     self.set_encrypted_passwd(userconfig.name,
325                                               userconfig.password)
326                 else:
327                     self.set_unencrypted_passwd(userconfig.name,
328                                                 userconfig.password)
329             else:
330                 self.set_empty_passwd(userconfig.name)
331         else:
332             raise errors.KsError("Invalid kickstart command: %s" \
333                                  % userconfig.__str__())
334
335     @apply_wrapper
336     def apply(self, user):
337         for userconfig in user.userList:
338             self.addUser(userconfig)
339
340 class ServicesConfig(KickstartConfig):
341     """A class to apply a kickstart services configuration to a system."""
342     @apply_wrapper
343     def apply(self, ksservices):
344         if not os.path.exists(self.path("/sbin/chkconfig")):
345             return
346         for s in ksservices.enabled:
347             self.call(["/sbin/chkconfig", s, "on"])
348         for s in ksservices.disabled:
349             self.call(["/sbin/chkconfig", s, "off"])
350
351 class XConfig(KickstartConfig):
352     """A class to apply a kickstart X configuration to a system."""
353     @apply_wrapper
354     def apply(self, ksxconfig):
355         if ksxconfig.startX and os.path.exists(self.path("/etc/inittab")):
356             f = open(self.path("/etc/inittab"), "rw+")
357             buf = f.read()
358             buf = buf.replace("id:3:initdefault", "id:5:initdefault")
359             f.seek(0)
360             f.write(buf)
361             f.close()
362         if ksxconfig.defaultdesktop:
363             self._check_sysconfig()
364             f = open(self.path("/etc/sysconfig/desktop"), "w")
365             f.write("DESKTOP="+ksxconfig.defaultdesktop+"\n")
366             f.close()
367
368 class DesktopConfig(KickstartConfig):
369     """A class to apply a kickstart desktop configuration to a system."""
370     @apply_wrapper
371     def apply(self, ksdesktop):
372         if ksdesktop.defaultdesktop:
373             self._check_sysconfig()
374             f = open(self.path("/etc/sysconfig/desktop"), "w")
375             f.write("DESKTOP="+ksdesktop.defaultdesktop+"\n")
376             f.close()
377             if os.path.exists(self.path("/etc/gdm/custom.conf")):
378                 f = open(self.path("/etc/skel/.dmrc"), "w")
379                 f.write("[Desktop]\n")
380                 f.write("Session="+ksdesktop.defaultdesktop.lower()+"\n")
381                 f.close()
382         if ksdesktop.session:
383             if os.path.exists(self.path("/etc/sysconfig/uxlaunch")):
384                 f = open(self.path("/etc/sysconfig/uxlaunch"), "a+")
385                 f.write("session="+ksdesktop.session.lower()+"\n")
386                 f.close()
387         if ksdesktop.autologinuser:
388             self._check_sysconfig()
389             f = open(self.path("/etc/sysconfig/desktop"), "a+")
390             f.write("AUTOLOGIN_USER=" + ksdesktop.autologinuser + "\n")
391             f.close()
392             if os.path.exists(self.path("/etc/gdm/custom.conf")):
393                 f = open(self.path("/etc/gdm/custom.conf"), "w")
394                 f.write("[daemon]\n")
395                 f.write("AutomaticLoginEnable=true\n")
396                 f.write("AutomaticLogin=" + ksdesktop.autologinuser + "\n")
397                 f.close()
398
399 class MoblinRepoConfig(KickstartConfig):
400     """A class to apply a kickstart desktop configuration to a system."""
401     def __create_repo_section(self, repo, type, fd):
402         baseurl = None
403         mirrorlist = None
404         reposuffix = {"base":"", "debuginfo":"-debuginfo", "source":"-source"}
405         reponame = repo.name + reposuffix[type]
406         if type == "base":
407             if repo.baseurl:
408                 baseurl = repo.baseurl
409             if repo.mirrorlist:
410                 mirrorlist = repo.mirrorlist
411
412         elif type == "debuginfo":
413             if repo.baseurl:
414                 if repo.baseurl.endswith("/"):
415                     baseurl = os.path.dirname(os.path.dirname(repo.baseurl))
416                 else:
417                     baseurl = os.path.dirname(repo.baseurl)
418                 baseurl += "/debug"
419
420             if repo.mirrorlist:
421                 variant = repo.mirrorlist[repo.mirrorlist.find("$"):]
422                 mirrorlist = repo.mirrorlist[0:repo.mirrorlist.find("$")]
423                 mirrorlist += "debug" + "-" + variant
424
425         elif type == "source":
426             if repo.baseurl:
427                 if repo.baseurl.endswith("/"):
428                     baseurl = os.path.dirname(
429                                  os.path.dirname(
430                                     os.path.dirname(repo.baseurl)))
431                 else:
432                     baseurl = os.path.dirname(os.path.dirname(repo.baseurl))
433                 baseurl += "/source"
434
435             if repo.mirrorlist:
436                 variant = repo.mirrorlist[repo.mirrorlist.find("$"):]
437                 mirrorlist = repo.mirrorlist[0:repo.mirrorlist.find("$")]
438                 mirrorlist += "source" + "-" + variant
439
440         fd.write("[" + reponame + "]\n")
441         fd.write("name=" + reponame + "\n")
442         fd.write("failovermethod=priority\n")
443         if baseurl:
444             auth_url = re.compile(AUTH_URL_PTN)
445             m = auth_url.match(baseurl)
446             if m:
447                 baseurl = "%s://%s" % (m.group('scheme'), m.group('url'))
448             fd.write("baseurl=" + baseurl + "\n")
449         if mirrorlist:
450             fd.write("mirrorlist=" + mirrorlist + "\n")
451         """ Skip saving proxy settings """
452         #if repo.proxy:
453         #    fd.write("proxy=" + repo.proxy + "\n")
454         #if repo.proxy_username:
455         #    fd.write("proxy_username=" + repo.proxy_username + "\n")
456         #if repo.proxy_password:
457         #    fd.write("proxy_password=" + repo.proxy_password + "\n")
458         if repo.gpgkey:
459             fd.write("gpgkey=" + repo.gpgkey + "\n")
460             fd.write("gpgcheck=1\n")
461         else:
462             fd.write("gpgcheck=0\n")
463         if type == "source" or type == "debuginfo" or repo.disable:
464             fd.write("enabled=0\n")
465         else:
466             fd.write("enabled=1\n")
467         fd.write("\n")
468
469     def __create_repo_file(self, repo, repodir):
470         fs.makedirs(self.path(repodir))
471         f = open(self.path(repodir + "/" + repo.name + ".repo"), "w")
472         self.__create_repo_section(repo, "base", f)
473         if repo.debuginfo:
474             self.__create_repo_section(repo, "debuginfo", f)
475         if repo.source:
476             self.__create_repo_section(repo, "source", f)
477         f.close()
478
479     @apply_wrapper
480     def apply(self, ksrepo, repodata, repourl):
481         for repo in ksrepo.repoList:
482             if repo.name in repourl:
483                 repo.baseurl = repourl[repo.name]
484             if repo.save:
485                 #self.__create_repo_file(repo, "/etc/yum.repos.d")
486                 self.__create_repo_file(repo, "/etc/zypp/repos.d")
487         """ Import repo gpg keys """
488         if repodata:
489             for repo in repodata:
490                 if repo['repokey']:
491                     runner.quiet(['rpm',
492                                   "--root=%s" % self.instroot,
493                                   "--import",
494                                   repo['repokey']])
495
496 class RPMMacroConfig(KickstartConfig):
497     """A class to apply the specified rpm macros to the filesystem"""
498     @apply_wrapper
499     def apply(self, ks):
500         if not ks:
501             return
502         if not os.path.exists(self.path("/etc/rpm")):
503             os.mkdir(self.path("/etc/rpm"))
504         f = open(self.path("/etc/rpm/macros.imgcreate"), "w+")
505         if exclude_docs(ks):
506             f.write("%_excludedocs 1\n")
507         f.write("%__file_context_path %{nil}\n")
508         if inst_langs(ks) != None:
509             f.write("%_install_langs ")
510             f.write(inst_langs(ks))
511             f.write("\n")
512         f.close()
513
514 class NetworkConfig(KickstartConfig):
515     """A class to apply a kickstart network configuration to a system."""
516     def write_ifcfg(self, network):
517         p = self.path("/etc/sysconfig/network-scripts/ifcfg-" + network.device)
518
519         f = file(p, "w+")
520         os.chmod(p, 0644)
521
522         f.write("DEVICE=%s\n" % network.device)
523         f.write("BOOTPROTO=%s\n" % network.bootProto)
524
525         if network.bootProto.lower() == "static":
526             if network.ip:
527                 f.write("IPADDR=%s\n" % network.ip)
528             if network.netmask:
529                 f.write("NETMASK=%s\n" % network.netmask)
530
531         if network.onboot:
532             f.write("ONBOOT=on\n")
533         else:
534             f.write("ONBOOT=off\n")
535
536         if network.essid:
537             f.write("ESSID=%s\n" % network.essid)
538
539         if network.ethtool:
540             if network.ethtool.find("autoneg") == -1:
541                 network.ethtool = "autoneg off " + network.ethtool
542             f.write("ETHTOOL_OPTS=%s\n" % network.ethtool)
543
544         if network.bootProto.lower() == "dhcp":
545             if network.hostname:
546                 f.write("DHCP_HOSTNAME=%s\n" % network.hostname)
547             if network.dhcpclass:
548                 f.write("DHCP_CLASSID=%s\n" % network.dhcpclass)
549
550         if network.mtu:
551             f.write("MTU=%s\n" % network.mtu)
552
553         f.close()
554
555     def write_wepkey(self, network):
556         if not network.wepkey:
557             return
558
559         p = self.path("/etc/sysconfig/network-scripts/keys-" + network.device)
560         f = file(p, "w+")
561         os.chmod(p, 0600)
562         f.write("KEY=%s\n" % network.wepkey)
563         f.close()
564
565     def write_sysconfig(self, useipv6, hostname, gateway):
566         path = self.path("/etc/sysconfig/network")
567         f = file(path, "w+")
568         os.chmod(path, 0644)
569
570         f.write("NETWORKING=yes\n")
571
572         if useipv6:
573             f.write("NETWORKING_IPV6=yes\n")
574         else:
575             f.write("NETWORKING_IPV6=no\n")
576
577         if hostname:
578             f.write("HOSTNAME=%s\n" % hostname)
579         else:
580             f.write("HOSTNAME=localhost.localdomain\n")
581
582         if gateway:
583             f.write("GATEWAY=%s\n" % gateway)
584
585         f.close()
586
587     def write_hosts(self, hostname):
588         localline = ""
589         if hostname and hostname != "localhost.localdomain":
590             localline += hostname + " "
591             l = hostname.split(".")
592             if len(l) > 1:
593                 localline += l[0] + " "
594         localline += "localhost.localdomain localhost"
595
596         path = self.path("/etc/hosts")
597         f = file(path, "w+")
598         os.chmod(path, 0644)
599         f.write("127.0.0.1\t\t%s\n" % localline)
600         f.write("::1\t\tlocalhost6.localdomain6 localhost6\n")
601         f.close()
602
603     def write_resolv(self, nodns, nameservers):
604         if nodns or not nameservers:
605             return
606
607         path = self.path("/etc/resolv.conf")
608         f = file(path, "w+")
609         os.chmod(path, 0644)
610
611         for ns in (nameservers):
612             if ns:
613                 f.write("nameserver %s\n" % ns)
614
615         f.close()
616
617     @apply_wrapper
618     def apply(self, ksnet):
619         fs.makedirs(self.path("/etc/sysconfig/network-scripts"))
620
621         useipv6 = False
622         nodns = False
623         hostname = None
624         gateway = None
625         nameservers = None
626
627         for network in ksnet.network:
628             if not network.device:
629                 raise errors.KsError("No --device specified with "
630                                             "network kickstart command")
631
632             if (network.onboot and network.bootProto.lower() != "dhcp" and
633                 not (network.ip and network.netmask)):
634                 raise errors.KsError("No IP address and/or netmask "
635                                             "specified with static "
636                                             "configuration for '%s'" %
637                                             network.device)
638
639             self.write_ifcfg(network)
640             self.write_wepkey(network)
641
642             if network.ipv6:
643                 useipv6 = True
644             if network.nodns:
645                 nodns = True
646
647             if network.hostname:
648                 hostname = network.hostname
649             if network.gateway:
650                 gateway = network.gateway
651
652             if network.nameserver:
653                 nameservers = network.nameserver.split(",")
654
655         self.write_sysconfig(useipv6, hostname, gateway)
656         self.write_hosts(hostname)
657         self.write_resolv(nodns, nameservers)
658
659 def use_installerfw(ks, feature):
660     """ Check if the installer framework has to be used for a feature
661     "feature". """
662
663     features = ks.handler.installerfw.features
664     if features:
665         if feature in features or "all" in features:
666             return True
667     return False
668
669 def get_image_size(ks, default = None):
670     __size = 0
671     for p in ks.handler.partition.partitions:
672         if p.mountpoint == "/" and p.size:
673             __size = p.size
674     if __size > 0:
675         return int(__size) * 1024L * 1024L
676     else:
677         return default
678
679 def get_image_fstype(ks, default = None):
680     for p in ks.handler.partition.partitions:
681         if p.mountpoint == "/" and p.fstype:
682             return p.fstype
683     return default
684
685 def get_image_fsopts(ks, default = None):
686     for p in ks.handler.partition.partitions:
687         if p.mountpoint == "/" and p.fsopts:
688             return p.fsopts
689     return default
690
691 def get_modules(ks):
692     devices = []
693     if isinstance(ks.handler.device, kscommands.device.FC3_Device):
694         devices.append(ks.handler.device)
695     else:
696         devices.extend(ks.handler.device.deviceList)
697
698     modules = []
699     for device in devices:
700         if not device.moduleName:
701             continue
702         modules.extend(device.moduleName.split(":"))
703
704     return modules
705
706 def get_timeout(ks, default = None):
707     if not hasattr(ks.handler.bootloader, "timeout"):
708         return default
709     if ks.handler.bootloader.timeout is None:
710         return default
711     return int(ks.handler.bootloader.timeout)
712
713 def get_kernel_args(ks, default = "ro rd.live.image"):
714     if not hasattr(ks.handler.bootloader, "appendLine"):
715         return default
716     if ks.handler.bootloader.appendLine is None:
717         return default
718     return "%s %s" %(default, ks.handler.bootloader.appendLine)
719
720 def get_menu_args(ks, default = ""):
721     if not hasattr(ks.handler.bootloader, "menus"):
722         return default
723     if ks.handler.bootloader.menus in (None, ""):
724         return default
725     return "%s" % ks.handler.bootloader.menus
726
727 def get_default_kernel(ks, default = None):
728     if not hasattr(ks.handler.bootloader, "default"):
729         return default
730     if not ks.handler.bootloader.default:
731         return default
732     return ks.handler.bootloader.default
733
734 RepoType = collections.namedtuple("Repo",
735                "name, baseurl, mirrorlist, includepkgs, excludepkgs, proxy, \
736                proxy_username, proxy_password, debuginfo, \
737                source, gpgkey, disable, ssl_verify, nocache, \
738                cost, priority")
739
740 def Repo(name, baseurl, mirrorlist=None, includepkgs=[], excludepkgs=[], proxy=None,
741          proxy_username=None, proxy_password=None, debuginfo=None,
742          source=None, gpgkey=None, disable=None, ssl_verify=None,
743          nocache=False, cost=None, priority=None):
744     return RepoType(name, baseurl, mirrorlist, includepkgs, excludepkgs, proxy,
745                     proxy_username, proxy_password, debuginfo,
746                     source, gpgkey, disable, ssl_verify, nocache,
747                     cost, priority)
748
749
750 def get_repos(ks, repo_urls=None, ignore_ksrepo=False):
751     repos = {}
752     for repodata in ks.handler.repo.repoList:
753         repo = {}
754         for field in RepoType._fields:
755             if hasattr(repodata, field) and getattr(repodata, field):
756                 repo[field] = getattr(repodata, field)
757
758         if hasattr(repodata, 'baseurl') and getattr(repodata, 'baseurl'):
759             repo['baseurl'] = SafeURL(getattr(repodata, 'baseurl'),
760                                       getattr(repodata, 'user', None),
761                                       getattr(repodata, 'passwd', None))
762
763         if 'name' in repo:
764             repos[repo['name']] = Repo(**repo)
765
766     if repo_urls:
767         if ignore_ksrepo:
768             repos = {}
769         for name, repo in repo_urls.items():
770             if 'baseurl' in repo:
771                 repo['baseurl'] = SafeURL(repo.get('baseurl'),
772                                           repo.get('user', None),
773                                           repo.get('passwd', None))
774             repos[name] = Repo(**repo)
775
776     return repos.values()
777
778 def convert_method_to_repo(ks):
779     try:
780         ks.handler.repo.methodToRepo()
781     except (AttributeError, kserrors.KickstartError):
782         pass
783
784 def get_attachment(ks, required=()):
785     return ks.handler.attachment.packageList + list(required)
786
787 def get_pre_packages(ks, required=()):
788     return ks.handler.prepackages.packageList + list(required)
789
790 def get_packages(ks, required=()):
791     return ks.handler.packages.packageList + list(required)
792
793 def get_groups(ks, required=()):
794     return ks.handler.packages.groupList + list(required)
795
796 def get_excluded(ks, required=()):
797     return ks.handler.packages.excludedList + list(required)
798
799 def get_partitions(ks):
800     return ks.handler.partition.partitions
801
802 def ignore_missing(ks):
803     return ks.handler.packages.handleMissing == ksconstants.KS_MISSING_IGNORE
804
805 def exclude_docs(ks):
806     return ks.handler.packages.excludeDocs
807
808 def inst_langs(ks):
809     if hasattr(ks.handler.packages, "instLange"):
810         return ks.handler.packages.instLange
811     elif hasattr(ks.handler.packages, "instLangs"):
812         return ks.handler.packages.instLangs
813     return ""
814
815 def get_post_scripts(ks):
816     scripts = []
817     for s in ks.handler.scripts:
818         if s.type != ksparser.KS_SCRIPT_POST:
819             continue
820         scripts.append(s)
821     return scripts
822
823 def get_sign_scripts(ks):
824     scripts = []
825     for s in ks.handler.scripts:
826         if s.type != ksparser.KS_SCRIPT_RUN:
827             continue
828         scripts.append(s)
829     return scripts
830 def add_repo(ks, repostr):
831     args = repostr.split()
832     repoobj = ks.handler.repo.parse(args[1:])
833     if repoobj and repoobj not in ks.handler.repo.repoList:
834         ks.handler.repo.repoList.append(repoobj)
835
836 def remove_all_repos(ks):
837     while len(ks.handler.repo.repoList) != 0:
838         del ks.handler.repo.repoList[0]
839
840 def remove_duplicate_repos(ks):
841     i = 0
842     j = i + 1
843     while True:
844         if len(ks.handler.repo.repoList) < 2:
845             break
846         if i >= len(ks.handler.repo.repoList) - 1:
847             break
848         name = ks.handler.repo.repoList[i].name
849         baseurl = ks.handler.repo.repoList[i].baseurl
850         if j < len(ks.handler.repo.repoList):
851             if (ks.handler.repo.repoList[j].name == name or \
852                 ks.handler.repo.repoList[j].baseurl == baseurl):
853                 del ks.handler.repo.repoList[j]
854             else:
855                 j += 1
856             if j >= len(ks.handler.repo.repoList):
857                 i += 1
858                 j = i + 1
859         else:
860             i += 1
861             j = i + 1
862
863 def resolve_groups(creatoropts, repometadata):
864     iszypp = False
865     if 'zypp' == creatoropts['pkgmgr']:
866         iszypp = True
867     ks = creatoropts['ks']
868
869     for repo in repometadata:
870         """ Mustn't replace group with package list if repo is ready for the
871             corresponding package manager.
872         """
873
874         if iszypp and repo["patterns"]:
875             continue
876         if not iszypp and repo["comps"]:
877             continue
878
879         # But we also must handle such cases, use zypp but repo only has comps,
880         # use yum but repo only has patterns, use zypp but use_comps is true,
881         # use yum but use_comps is false.
882         groupfile = None
883         if iszypp and repo["comps"]:
884             groupfile = repo["comps"]
885             get_pkglist_handler = misc.get_pkglist_in_comps
886         if not iszypp and repo["patterns"]:
887             groupfile = repo["patterns"]
888             get_pkglist_handler = misc.get_pkglist_in_patterns
889
890         if groupfile:
891             i = 0
892             while True:
893                 if i >= len(ks.handler.packages.groupList):
894                     break
895                 pkglist = get_pkglist_handler(
896                                         ks.handler.packages.groupList[i].name,
897                                         groupfile)
898                 if pkglist:
899                     del ks.handler.packages.groupList[i]
900                     for pkg in pkglist:
901                         if pkg not in ks.handler.packages.packageList:
902                             ks.handler.packages.packageList.append(pkg)
903                 else:
904                     i = i + 1