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