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