1 |
# |
2 |
# backend.py: Interface for installation backends |
3 |
# |
4 |
# Copyright (C) 2005, 2006, 2007 Red Hat, Inc. All rights reserved. |
5 |
# |
6 |
# This program is free software; you can redistribute it and/or modify |
7 |
# it under the terms of the GNU General Public License as published by |
8 |
# the Free Software Foundation; either version 2 of the License, or |
9 |
# (at your option) any later version. |
10 |
# |
11 |
# This program is distributed in the hope that it will be useful, |
12 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 |
# GNU General Public License for more details. |
15 |
# |
16 |
# You should have received a copy of the GNU General Public License |
17 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
18 |
# |
19 |
# Author(s): Paul Nasrat <pnasrat@redhat.com> |
20 |
# Jeremy Katz <katzj@redhat.com> |
21 |
# |
22 |
|
23 |
import glob |
24 |
import shutil |
25 |
import iutil |
26 |
import os, sys |
27 |
import logging |
28 |
from syslogd import syslog |
29 |
from constants import * |
30 |
|
31 |
import isys |
32 |
import kickstart |
33 |
import packages |
34 |
import storage |
35 |
|
36 |
from flags import flags |
37 |
log = logging.getLogger("anaconda") |
38 |
|
39 |
import gettext |
40 |
_ = lambda x: gettext.ldgettext("anaconda", x) |
41 |
|
42 |
class AnacondaBackend: |
43 |
def __init__(self, anaconda): |
44 |
"""Abstract backend class all backends should inherit from this |
45 |
@param instPath: root path for the installation to occur""" |
46 |
|
47 |
self.instPath = anaconda.rootPath |
48 |
self.instLog = None |
49 |
self.modeText = "" |
50 |
|
51 |
# some backends may not support upgrading |
52 |
self.supportsUpgrades = True |
53 |
self.supportsPackageSelection = False |
54 |
|
55 |
# some backends may have a special case for rootfs formatting |
56 |
# FIXME: we should handle this a little more elegantly |
57 |
self.skipFormatRoot = False |
58 |
self.rootFsType = None |
59 |
|
60 |
self._loopbackFile = None |
61 |
|
62 |
def postAction(self, anaconda): |
63 |
pass |
64 |
|
65 |
def doPreSelection(self, intf, id, instPath): |
66 |
pass |
67 |
|
68 |
def doPostSelection(self, anaconda): |
69 |
pass |
70 |
|
71 |
def doPreInstall(self, anaconda): |
72 |
self.initLog(anaconda.id, anaconda.rootPath) |
73 |
|
74 |
def copyFirmware(self, anaconda): |
75 |
# Multiple driver disks may be loaded, so we need to glob for all |
76 |
# the firmware files in the common DD firmware directory |
77 |
for f in glob.glob(DD_FIRMWARE+"/*"): |
78 |
try: |
79 |
shutil.copyfile(f, "%s/lib/firmware/" % anaconda.rootPath) |
80 |
except IOError, e: |
81 |
log.error("Could not copy firmware file %s: %s" % (f, e.strerror)) |
82 |
|
83 |
def doPostInstall(self, anaconda): |
84 |
has_iscsi_disk = False |
85 |
|
86 |
# See if we have an iscsi disk. If we do we rerun mkinitrd, as |
87 |
# the initrd might need iscsi-initiator-utils, and chances are |
88 |
# it was not installed yet the first time mkinitrd was run, as |
89 |
# mkinitrd does not require it. |
90 |
root = anaconda.id.storage.rootDevice |
91 |
disks = anaconda.id.storage.devicetree.getDevicesByType("iscsi") |
92 |
for disk in disks: |
93 |
if root.dependsOn(disk): |
94 |
has_iscsi_disk = True |
95 |
break |
96 |
|
97 |
#always copy the firmware files from DD |
98 |
self.copyFirmware(anaconda) |
99 |
|
100 |
if anaconda.id.extraModules or has_iscsi_disk: |
101 |
for (n, arch, tag) in self.kernelVersionList(anaconda.rootPath): |
102 |
packages.recreateInitrd(n, anaconda.rootPath) |
103 |
|
104 |
#copy RPMS |
105 |
for d in glob.glob(DD_RPMS): |
106 |
try: |
107 |
shutil.copytree(d, anaconda.rootPath + "/root/" + os.path.basename(d)) |
108 |
except OSError: |
109 |
log.error("Couldn't copy %s to %s" % (d, anaconda.rootPath + "/root/" + os.path.basename(d))) |
110 |
|
111 |
#copy modules and firmware |
112 |
if os.path.exists(DD_ALL): |
113 |
try: |
114 |
shutil.copytree(DD_ALL, anaconda.rootPath + "/root/DD") |
115 |
except OSError, e: |
116 |
log.error("Couldn't copy %s to %s" % (DD_ALL, anaconda.rootPath + "/root/DD")) |
117 |
|
118 |
storage.writeEscrowPackets(anaconda) |
119 |
|
120 |
sys.stdout.flush() |
121 |
syslog.stop() |
122 |
|
123 |
def doInstall(self, anaconda): |
124 |
log.warning("doInstall not implemented for backend!") |
125 |
raise NotImplementedError |
126 |
|
127 |
def initLog(self, id, instPath): |
128 |
upgrade = id.getUpgrade() |
129 |
|
130 |
if not os.path.isdir(instPath + "/root"): |
131 |
iutil.mkdirChain(instPath + "/root") |
132 |
|
133 |
if upgrade: |
134 |
logname = '/root/upgrade.log' |
135 |
else: |
136 |
logname = '/root/install.log' |
137 |
|
138 |
instLogName = instPath + logname |
139 |
try: |
140 |
shutil.rmtree (instLogName) |
141 |
except OSError: |
142 |
pass |
143 |
|
144 |
self.instLog = open(instLogName, "w+") |
145 |
|
146 |
syslogname = "%s%s.syslog" % (instPath, logname) |
147 |
try: |
148 |
shutil.rmtree (syslogname) |
149 |
except OSError: |
150 |
pass |
151 |
syslog.start (instPath, syslogname) |
152 |
|
153 |
if upgrade: |
154 |
self.modeText = _("Upgrading %s\n") |
155 |
else: |
156 |
self.modeText = _("Installing %s\n") |
157 |
|
158 |
def kernelVersionList(self, rootPath="/"): |
159 |
return [] |
160 |
|
161 |
def getMinimumSizeMB(self, part): |
162 |
"""Return the minimal size for part in megabytes if we can.""" |
163 |
return 0 |
164 |
|
165 |
def doBackendSetup(self, anaconda): |
166 |
log.warning("doBackendSetup not implemented for backend!") |
167 |
raise NotImplementedError |
168 |
|
169 |
def groupExists(self, group): |
170 |
log.warning("groupExists not implemented for backend!") |
171 |
raise NotImplementedError |
172 |
|
173 |
def selectGroup(self, group, *args): |
174 |
log.warning("selectGroup not implemented for backend!") |
175 |
raise NotImplementedError |
176 |
|
177 |
def deselectGroup(self, group, *args): |
178 |
log.warning("deselectGroup not implemented for backend!") |
179 |
raise NotImplementedError |
180 |
|
181 |
def packageExists(self, pkg): |
182 |
log.warning("packageExists not implemented for backend!") |
183 |
raise NotImplementedError |
184 |
|
185 |
def selectPackage(self, pkg, *args): |
186 |
log.warning("selectPackage not implemented for backend!") |
187 |
raise NotImplementedError |
188 |
|
189 |
def deselectPackage(self, pkg, *args): |
190 |
log.warning("deselectPackage not implemented for backend!") |
191 |
raise NotImplementedError |
192 |
|
193 |
def getDefaultGroups(self, anaconda): |
194 |
log.warning("getDefaultGroups not implemented for backend!") |
195 |
raise NotImplementedError |
196 |
|
197 |
def resetPackageSelections(self): |
198 |
# we just leave this one unimplemented if it's not needed |
199 |
pass |
200 |
|
201 |
# write out the %packages section of anaconda-ks.cfg |
202 |
def writePackagesKS(self, f, anaconda): |
203 |
log.warning("writePackagesKS not implemented for backend!") |
204 |
raise NotImplementedError |
205 |
|
206 |
# write out any config files that live on the installed system |
207 |
# (e.g., /etc/yum.repos.d/* files) |
208 |
def writeConfiguration(self): |
209 |
log.warning("writeConfig not implemented for backend!") |
210 |
raise NotImplementedError |
211 |
|
212 |
# write out any other kickstart bits the backend requires - no warning |
213 |
# here because this may not be needed |
214 |
def writeKS(self, f): |
215 |
pass |
216 |
|
217 |
def getRequiredMedia(self): |
218 |
log.warning("getRequiredMedia not implmented for backend!") |
219 |
raise NotImplementedError |
220 |
|
221 |
def complete(self, anaconda): |
222 |
pass |
223 |
|
224 |
def doBackendSetup(anaconda): |
225 |
if anaconda.backend.doBackendSetup(anaconda) == DISPATCH_BACK: |
226 |
return DISPATCH_BACK |
227 |
|
228 |
if anaconda.id.upgrade: |
229 |
anaconda.backend.checkSupportedUpgrade(anaconda) |
230 |
iutil.writeRpmPlatform(anaconda.rootPath) |
231 |
|
232 |
def doPostSelection(anaconda): |
233 |
return anaconda.backend.doPostSelection(anaconda) |
234 |
|
235 |
def doPreInstall(anaconda): |
236 |
anaconda.backend.doPreInstall(anaconda) |
237 |
|
238 |
def doPostInstall(anaconda): |
239 |
anaconda.backend.doPostInstall(anaconda) |
240 |
|
241 |
def doInstall(anaconda): |
242 |
return anaconda.backend.doInstall(anaconda) |
243 |
|
244 |
# does this need to be per-backend? we'll just leave here until it does :) |
245 |
def doBasePackageSelect(anaconda): |
246 |
if anaconda.isKickstart: |
247 |
anaconda.backend.resetPackageSelections() |
248 |
kickstart.selectPackages(anaconda) |
249 |
else: |
250 |
anaconda.backend.resetPackageSelections() |
251 |
anaconda.id.instClass.setPackageSelection(anaconda) |
252 |
anaconda.id.instClass.setGroupSelection(anaconda) |
253 |
|
254 |
def writeConfiguration(anaconda): |
255 |
log.info("Writing main configuration") |
256 |
anaconda.id.write() |
257 |
anaconda.backend.writeConfiguration() |