/[smeserver]/cdrom.image/sme9/updates/storage/deviceaction.py
ViewVC logotype

Contents of /cdrom.image/sme9/updates/storage/deviceaction.py

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.2 - (show annotations) (download) (as text)
Sun Dec 22 04:27:50 2013 UTC (10 years, 7 months ago) by wellsi
Branch: MAIN
CVS Tags: HEAD
Changes since 1.1: +0 -0 lines
Content type: text/x-python
FILE REMOVED
anaconda updates now handled via patches

1 # deviceaction.py
2 # Device modification action classes for anaconda's storage configuration
3 # module.
4 #
5 # Copyright (C) 2009 Red Hat, Inc.
6 #
7 # This copyrighted material is made available to anyone wishing to use,
8 # modify, copy, or redistribute it subject to the terms and conditions of
9 # the GNU General Public License v.2, or (at your option) any later version.
10 # This program is distributed in the hope that it will be useful, but WITHOUT
11 # ANY WARRANTY expressed or implied, including the implied warranties of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
13 # Public License for more details. You should have received a copy of the
14 # GNU General Public License along with this program; if not, write to the
15 # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16 # 02110-1301, USA. Any Red Hat trademarks that are incorporated in the
17 # source code or documentation are not subject to the GNU General Public
18 # License and may only be used or replicated with the express permission of
19 # Red Hat, Inc.
20 #
21 # Red Hat Author(s): Dave Lehman <dlehman@redhat.com>
22 #
23
24 from udev import *
25 import math
26
27 from devices import StorageDevice, PartitionDevice
28 from formats import getFormat
29 from errors import *
30 from parted import partitionFlag, PARTITION_LBA
31
32 import gettext
33 _ = lambda x: gettext.ldgettext("anaconda", x)
34
35 import logging
36 log = logging.getLogger("storage")
37
38
39 # The values are just hints as to the ordering.
40 # Eg: fsmod and devmod ordering depends on the mod (shrink -v- grow)
41 ACTION_TYPE_NONE = 0
42 ACTION_TYPE_DESTROY = 1000
43 ACTION_TYPE_RESIZE = 500
44 ACTION_TYPE_MIGRATE = 250
45 ACTION_TYPE_CREATE = 100
46
47 action_strings = {ACTION_TYPE_NONE: "None",
48 ACTION_TYPE_DESTROY: "Destroy",
49 ACTION_TYPE_RESIZE: "Resize",
50 ACTION_TYPE_MIGRATE: "Migrate",
51 ACTION_TYPE_CREATE: "Create"}
52
53 ACTION_OBJECT_NONE = 0
54 ACTION_OBJECT_FORMAT = 1
55 ACTION_OBJECT_DEVICE = 2
56
57 object_strings = {ACTION_OBJECT_NONE: "None",
58 ACTION_OBJECT_FORMAT: "Format",
59 ACTION_OBJECT_DEVICE: "Device"}
60
61 RESIZE_SHRINK = 88
62 RESIZE_GROW = 89
63
64 resize_strings = {RESIZE_SHRINK: "Shrink",
65 RESIZE_GROW: "Grow"}
66
67 def action_type_from_string(type_string):
68 if type_string is None:
69 return None
70
71 for (k,v) in action_strings.items():
72 if v.lower() == type_string.lower():
73 return k
74
75 return resize_type_from_string(type_string)
76
77 def action_object_from_string(type_string):
78 if type_string is None:
79 return None
80
81 for (k,v) in object_strings.items():
82 if v.lower() == type_string.lower():
83 return k
84
85 def resize_type_from_string(type_string):
86 if type_string is None:
87 return None
88
89 for (k,v) in resize_strings.items():
90 if v.lower() == type_string.lower():
91 return k
92
93 class DeviceAction(object):
94 """ An action that will be carried out in the future on a Device.
95
96 These classes represent actions to be performed on devices or
97 filesystems.
98
99 The operand Device instance will be modified according to the
100 action, but no changes will be made to the underlying device or
101 filesystem until the DeviceAction instance's execute method is
102 called. The DeviceAction instance's cancel method should reverse
103 any modifications made to the Device instance's attributes.
104
105 If the Device instance represents a pre-existing device, the
106 constructor should call any methods or set any attributes that the
107 action will eventually change. Device/DeviceFormat classes should verify
108 that the requested modifications are reasonable and raise an
109 exception if not.
110
111 Only one action of any given type/object pair can exist for any
112 given device at any given time. This is enforced by the
113 DeviceTree.
114
115 Basic usage:
116
117 a = DeviceAction(dev)
118 a.execute()
119
120 OR
121
122 a = DeviceAction(dev)
123 a.cancel()
124
125
126 XXX should we back up the device with a deep copy for forcibly
127 cancelling actions?
128
129 The downside is that we lose any checking or verification that
130 would get done when resetting the Device instance's attributes to
131 their original values.
132
133 The upside is that we would be guaranteed to achieve a total
134 reversal. No chance of, eg: resizes ending up altering Device
135 size due to rounding or other miscalculation.
136 """
137 type = ACTION_TYPE_NONE
138 obj = ACTION_OBJECT_NONE
139
140 def __init__(self, device):
141 if not isinstance(device, StorageDevice):
142 raise ValueError("arg 1 must be a StorageDevice instance")
143 self.device = device
144
145
146 def execute(self, intf=None):
147 """ perform the action """
148 pass
149
150 def cancel(self):
151 """ cancel the action """
152 pass
153
154 def isDestroy(self):
155 return self.type == ACTION_TYPE_DESTROY
156
157 def isCreate(self):
158 return self.type == ACTION_TYPE_CREATE
159
160 def isMigrate(self):
161 return self.type == ACTION_TYPE_MIGRATE
162
163 def isResize(self):
164 return self.type == ACTION_TYPE_RESIZE
165
166 def isShrink(self):
167 return (self.type == ACTION_TYPE_RESIZE and self.dir == RESIZE_SHRINK)
168
169 def isGrow(self):
170 return (self.type == ACTION_TYPE_RESIZE and self.dir == RESIZE_GROW)
171
172 def isDevice(self):
173 return self.obj == ACTION_OBJECT_DEVICE
174
175 def isFormat(self):
176 return self.obj == ACTION_OBJECT_FORMAT
177
178 @property
179 def format(self):
180 return self.device.format
181
182 def __str__(self):
183 s = "%s %s" % (action_strings[self.type], object_strings[self.obj])
184 if self.isResize():
185 s += " (%s)" % resize_strings[self.dir]
186 if self.isFormat():
187 s += " %s on" % self.format.type
188 if self.isMigrate():
189 s += " to %s" % self.format.migrationTarget
190 s += " %s %s (id %d)" % (self.device.type, self.device.name,
191 self.device.id)
192 return s
193
194 class ActionCreateDevice(DeviceAction):
195 """ Action representing the creation of a new device. """
196 type = ACTION_TYPE_CREATE
197 obj = ACTION_OBJECT_DEVICE
198
199 def __init__(self, device):
200 # FIXME: assert device.fs is None
201 DeviceAction.__init__(self, device)
202
203 def execute(self, intf=None):
204 self.device.create(intf=intf)
205
206
207 class ActionDestroyDevice(DeviceAction):
208 """ An action representing the deletion of an existing device. """
209 type = ACTION_TYPE_DESTROY
210 obj = ACTION_OBJECT_DEVICE
211
212 def __init__(self, device):
213 # XXX should we insist that device.fs be None?
214 DeviceAction.__init__(self, device)
215 if device.exists:
216 device.teardown()
217
218 def execute(self, intf=None):
219 self.device.destroy()
220
221 # Make sure libparted does not keep cached info for this device
222 # and returns it when we create a new device with the same name
223 if self.device.partedDevice:
224 self.device.partedDevice.removeFromCache()
225
226
227 class ActionResizeDevice(DeviceAction):
228 """ An action representing the resizing of an existing device. """
229 type = ACTION_TYPE_RESIZE
230 obj = ACTION_OBJECT_DEVICE
231
232 def __init__(self, device, newsize):
233 currentSize = long(math.floor(device.currentSize))
234 if currentSize == newsize:
235 raise ValueError("new size same as old size")
236
237 if not device.resizable:
238 raise ValueError("device is not resizable")
239
240 DeviceAction.__init__(self, device)
241 if newsize > currentSize:
242 self.dir = RESIZE_GROW
243 else:
244 self.dir = RESIZE_SHRINK
245 self.origsize = device.targetSize
246 self.device.targetSize = newsize
247
248 def execute(self, intf=None):
249 self.device.resize(intf=intf)
250
251 def cancel(self):
252 self.device.targetSize = self.origsize
253
254
255 class ActionCreateFormat(DeviceAction):
256 """ An action representing creation of a new filesystem. """
257 type = ACTION_TYPE_CREATE
258 obj = ACTION_OBJECT_FORMAT
259
260 def __init__(self, device, format=None):
261 DeviceAction.__init__(self, device)
262 if format:
263 self.origFormat = device.format
264 if self.device.format.exists:
265 self.device.format.teardown()
266 self.device.format = format
267 else:
268 self.origFormat = getFormat(None)
269
270 def execute(self, intf=None):
271 self.device.setup()
272
273 if isinstance(self.device, PartitionDevice):
274 for flag in partitionFlag.keys():
275 # Keep the LBA flag on pre-existing partitions
276 if flag in [ PARTITION_LBA, self.format.partedFlag ]:
277 continue
278 self.device.unsetFlag(flag)
279
280 if self.format.partedFlag is not None:
281 self.device.setFlag(self.format.partedFlag)
282
283 if self.format.partedSystem is not None:
284 self.device.partedPartition.system = self.format.partedSystem
285
286 self.device.disk.format.commitToDisk()
287
288 self.device.format.create(intf=intf,
289 device=self.device.path,
290 options=self.device.formatArgs)
291 # Get the UUID now that the format is created
292 udev_settle()
293 self.device.updateSysfsPath()
294 info = udev_get_block_device(self.device.sysfsPath)
295 self.device.format.uuid = udev_device_get_uuid(info)
296
297 def cancel(self):
298 self.device.format = self.origFormat
299
300
301 class ActionDestroyFormat(DeviceAction):
302 """ An action representing the removal of an existing filesystem.
303
304 XXX this seems unnecessary
305 """
306 type = ACTION_TYPE_DESTROY
307 obj = ACTION_OBJECT_FORMAT
308
309 def __init__(self, device):
310 DeviceAction.__init__(self, device)
311 self.origFormat = self.device.format
312 if device.format.exists:
313 device.format.teardown()
314 self.device.format = None
315
316 def execute(self, intf=None):
317 """ wipe the filesystem signature from the device """
318 if self.origFormat:
319 self.device.setup(orig=True)
320 self.origFormat.destroy()
321 udev_settle()
322 self.device.teardown()
323
324 def cancel(self):
325 self.device.format = self.origFormat
326
327 @property
328 def format(self):
329 return self.origFormat
330
331
332 class ActionResizeFormat(DeviceAction):
333 """ An action representing the resizing of an existing filesystem.
334
335 XXX Do we even want to support resizing of a filesystem without
336 also resizing the device it resides on?
337 """
338 type = ACTION_TYPE_RESIZE
339 obj = ACTION_OBJECT_FORMAT
340
341 def __init__(self, device, newsize):
342 if long(math.floor(device.format.targetSize)) == newsize:
343 raise ValueError("new size same as old size")
344
345 DeviceAction.__init__(self, device)
346 if newsize > long(math.floor(device.format.currentSize)):
347 self.dir = RESIZE_GROW
348 else:
349 self.dir = RESIZE_SHRINK
350 self.origSize = self.device.format.targetSize
351 self.device.format.targetSize = newsize
352
353 def execute(self, intf=None):
354 self.device.setup(orig=True)
355 self.device.format.doResize(intf=intf)
356
357 def cancel(self):
358 self.device.format.targetSize = self.origSize
359
360 class ActionMigrateFormat(DeviceAction):
361 """ An action representing the migration of an existing filesystem. """
362 type = ACTION_TYPE_MIGRATE
363 obj = ACTION_OBJECT_FORMAT
364
365 def __init__(self, device):
366 if not device.format.migratable or not device.format.exists:
367 raise ValueError("device format is not migratable")
368
369 DeviceAction.__init__(self, device)
370 self.device.format.migrate = True
371
372 def execute(self, intf=None):
373 self.device.setup(orig=True)
374 self.device.format.doMigrate(intf=intf)
375
376 def cancel(self):
377 self.device.format.migrate = False
378

admin@koozali.org
ViewVC Help
Powered by ViewVC 1.2.1 RSS 2.0 feed