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