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