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