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