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