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