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