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

Annotation of /cdrom.image/sme9/updates/storage/formats/__init__.py

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


Revision 1.1 - (hide annotations) (download) (as text)
Sun Oct 20 23:12:54 2013 UTC (10 years, 8 months ago) by charliebrady
Branch: MAIN
Content type: text/x-python
Add devicelibs and formats subdirectories of storage, and contained .py
files, in preparation to modifying to allow degraded RAID install.

1 charliebrady 1.1 # __init__.py
2     # Entry point for anaconda storage formats subpackage.
3     #
4     # Copyright (C) 2009 Red Hat, Inc.
5     #
6     # This copyrighted material is made available to anyone wishing to use,
7     # modify, copy, or redistribute it subject to the terms and conditions of
8     # the GNU General Public License v.2, or (at your option) any later version.
9     # This program is distributed in the hope that it will be useful, but WITHOUT
10     # ANY WARRANTY expressed or implied, including the implied warranties of
11     # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
12     # Public License for more details. You should have received a copy of the
13     # GNU General Public License along with this program; if not, write to the
14     # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15     # 02110-1301, USA. Any Red Hat trademarks that are incorporated in the
16     # source code or documentation are not subject to the GNU General Public
17     # License and may only be used or replicated with the express permission of
18     # Red Hat, Inc.
19     #
20     # Red Hat Author(s): Dave Lehman <dlehman@redhat.com>
21     #
22    
23     import os
24    
25     from iutil import notify_kernel, get_sysfs_path_by_name
26     from baseudev import udev_get_device
27     from ..storage_log import log_method_call
28     from ..errors import *
29     from ..devicelibs.dm import dm_node_from_name
30     from ..udev import udev_device_get_major, udev_device_get_minor
31    
32     import gettext
33     _ = lambda x: gettext.ldgettext("anaconda", x)
34    
35     import logging
36     log = logging.getLogger("storage")
37    
38    
39     device_formats = {}
40     def register_device_format(fmt_class):
41     if not issubclass(fmt_class, DeviceFormat):
42     raise ValueError("arg1 must be a subclass of DeviceFormat")
43    
44     device_formats[fmt_class._type] = fmt_class
45     log.debug("registered device format class %s as %s" % (fmt_class.__name__,
46     fmt_class._type))
47    
48     default_fstypes = ("ext4", "ext3", "ext2")
49     def get_default_filesystem_type(boot=None):
50     import platform
51    
52     if boot:
53     fstypes = [platform.getPlatform(None).defaultBootFSType]
54     else:
55     fstypes = default_fstypes
56    
57     for fstype in fstypes:
58     try:
59     supported = get_device_format_class(fstype).supported
60     except AttributeError:
61     supported = None
62    
63     if supported:
64     return fstype
65    
66     raise DeviceFormatError("None of %s is supported by your kernel" % ",".join(fstypes))
67    
68     def getFormat(fmt_type, *args, **kwargs):
69     """ Return a DeviceFormat instance based on fmt_type and args.
70    
71     Given a device format type and a set of constructor arguments,
72     return a DeviceFormat instance.
73    
74     Return None if no suitable format class is found.
75    
76     Arguments:
77    
78     fmt_type -- the name of the format type (eg: 'ext3', 'swap')
79    
80     Keyword Arguments:
81    
82     The keyword arguments may vary according to the format type,
83     but here is the common set:
84    
85     device -- path to the device on which the format resides
86     uuid -- the UUID of the (preexisting) formatted device
87     exists -- whether or not the format exists on the device
88    
89     """
90     fmt_class = get_device_format_class(fmt_type)
91     fmt = None
92     if fmt_class:
93     fmt = fmt_class(*args, **kwargs)
94     try:
95     className = fmt.__class__.__name__
96     except AttributeError:
97     className = None
98     log.debug("getFormat('%s') returning %s instance" % (fmt_type, className))
99     return fmt
100    
101     def collect_device_format_classes():
102     """ Pick up all device format classes from this directory.
103    
104     Note: Modules must call register_device_format(FormatClass) in
105     order for the format class to be picked up.
106     """
107     dir = os.path.dirname(__file__)
108     for module_file in os.listdir(dir):
109     # make sure we're not importing this module
110     if module_file.endswith(".py") and module_file != __file__:
111     mod_name = module_file[:-3]
112     # imputil is deprecated in python 2.6
113     try:
114     globals()[mod_name] = __import__(mod_name, globals(), locals(), [], -1)
115     except ImportError, e:
116     log.debug("import of device format module '%s' failed" % mod_name)
117    
118     def get_device_format_class(fmt_type):
119     """ Return an appropriate format class based on fmt_type. """
120     if not device_formats:
121     collect_device_format_classes()
122    
123     fmt = device_formats.get(fmt_type)
124     if not fmt:
125     for fmt_class in device_formats.values():
126     if fmt_type and fmt_type == fmt_class._name:
127     fmt = fmt_class
128     break
129     elif fmt_type in fmt_class._udevTypes:
130     fmt = fmt_class
131     break
132    
133     # default to no formatting, AKA "Unknown"
134     if not fmt:
135     fmt = DeviceFormat
136    
137     return fmt
138    
139     class DeviceFormat(object):
140     """ Generic device format. """
141     _type = None
142     _name = "Unknown"
143     _udevTypes = []
144     partedFlag = None
145     partedSystem = None
146     _formattable = False # can be formatted
147     _supported = False # is supported
148     _linuxNative = False # for clearpart
149     _packages = [] # required packages
150     _services = [] # required services
151     _resizable = False # can be resized
152     _bootable = False # can be used as boot
153     _migratable = False # can be migrated
154     _maxSize = 0 # maximum size in MB
155     _minSize = 0 # minimum size in MB
156     _dump = False
157     _check = False
158     _hidden = False # hide devices with this formatting?
159    
160     def __init__(self, *args, **kwargs):
161     """ Create a DeviceFormat instance.
162    
163     Keyword Arguments:
164    
165     device -- path to the underlying device
166     uuid -- this format's UUID
167     exists -- indicates whether this is an existing format
168    
169     """
170     self.device = kwargs.get("device")
171     self.uuid = kwargs.get("uuid")
172     self.exists = kwargs.get("exists")
173     self.options = kwargs.get("options")
174     self._majorminor = None
175     self._migrate = False
176    
177     # don't worry about existence if this is a DeviceFormat instance
178     #if self.__class__ is DeviceFormat:
179     # self.exists = True
180    
181     def __str__(self):
182     s = ("%(classname)s instance (%(id)s) --\n"
183     " type = %(type)s name = %(name)s status = %(status)s\n"
184     " device = %(device)s uuid = %(uuid)s exists = %(exists)s\n"
185     " options = %(options)s supported = %(supported)s"
186     " formattable = %(format)s resizable = %(resize)s\n" %
187     {"classname": self.__class__.__name__, "id": "%#x" % id(self),
188     "type": self.type, "name": self.name, "status": self.status,
189     "device": self.device, "uuid": self.uuid, "exists": self.exists,
190     "options": self.options, "supported": self.supported,
191     "format": self.formattable, "resize": self.resizable})
192     return s
193    
194     @property
195     def dict(self):
196     d = {"type": self.type, "name": self.name, "device": self.device,
197     "uuid": self.uuid, "exists": self.exists,
198     "options": self.options, "supported": self.supported,
199     "resizable": self.resizable}
200     return d
201    
202     def _setOptions(self, options):
203     self._options = options
204    
205     def _getOptions(self):
206     return self._options
207    
208     options = property(_getOptions, _setOptions)
209    
210     def _setDevice(self, devspec):
211     if devspec and not devspec.startswith("/"):
212     raise ValueError("device must be a fully qualified path")
213     self._device = devspec
214    
215     def _getDevice(self):
216     return self._device
217    
218     device = property(lambda f: f._getDevice(),
219     lambda f,d: f._setDevice(d),
220     doc="Full path the device this format occupies")
221    
222     @property
223     def name(self):
224     if self._name:
225     name = self._name
226     else:
227     name = self.type
228     return name
229    
230     @property
231     def type(self):
232     return self._type
233    
234     def probe(self):
235     log_method_call(self, device=self.device,
236     type=self.type, status=self.status)
237    
238     def notifyKernel(self):
239     log_method_call(self, device=self.device,
240     type=self.type)
241     if not self.device:
242     return
243    
244     if self.device.startswith("/dev/mapper/"):
245     try:
246     name = dm_node_from_name(os.path.basename(self.device))
247     except Exception, e:
248     log.warning("failed to get dm node for %s" % self.device)
249     return
250     else:
251     name = self.device
252    
253     path = get_sysfs_path_by_name(name)
254     try:
255     notify_kernel(path, action="change")
256     except Exception, e:
257     log.warning("failed to notify kernel of change: %s" % e)
258    
259     def cacheMajorminor(self):
260     """ Cache the value of self.majorminor.
261    
262     Once a device node of this format's device disappears (for instance
263     after a teardown), it is no longer possible to figure out the value
264     of self.majorminor pseudo-unique string. Call this method before
265     that happens for caching this.
266     """
267     self._majorminor = None
268     try:
269     self.majorminor # this does the caching
270     except StorageError:
271     # entirely possible there's no majorminor, for instance an
272     # LVMVolumeGroup has got no device node and no sysfs path. In this
273     # case obviously, calling majorminor of this object later raises an
274     # exception.
275     pass
276     return self._majorminor
277    
278     def create(self, *args, **kwargs):
279     log_method_call(self, device=self.device,
280     type=self.type, status=self.status)
281     # allow late specification of device path
282     device = kwargs.get("device")
283     if device:
284     self.device = device
285    
286     if not os.path.exists(self.device):
287     raise FormatCreateError("invalid device specification", self.device)
288    
289     def destroy(self, *args, **kwargs):
290     log_method_call(self, device=self.device,
291     type=self.type, status=self.status)
292     # zero out the 1MB at the beginning and end of the device in the
293     # hope that it will wipe any metadata from filesystems that
294     # previously occupied this device
295     log.debug("zeroing out beginning and end of %s..." % self.device)
296     fd = None
297    
298     try:
299     fd = os.open(self.device, os.O_RDWR)
300     buf = '\0' * 1024 * 1024
301     os.write(fd, buf)
302     os.lseek(fd, -1024 * 1024, 2)
303     os.write(fd, buf)
304     os.close(fd)
305     except OSError as e:
306     if getattr(e, "errno", None) == 28: # No space left in device
307     pass
308     else:
309     log.error("error zeroing out %s: %s" % (self.device, e))
310    
311     if fd:
312     os.close(fd)
313     except Exception as e:
314     log.error("error zeroing out %s: %s" % (self.device, e))
315     if fd:
316     os.close(fd)
317    
318     self.exists = False
319    
320     def setup(self, *args, **kwargs):
321     log_method_call(self, device=self.device,
322     type=self.type, status=self.status)
323    
324     if not self.exists:
325     raise FormatSetupError("format has not been created")
326    
327     if self.status:
328     return
329    
330     # allow late specification of device path
331     device = kwargs.get("device")
332     if device:
333     self.device = device
334    
335     if not self.device or not os.path.exists(self.device):
336     raise FormatSetupError("invalid device specification")
337    
338     def teardown(self, *args, **kwargs):
339     log_method_call(self, device=self.device,
340     type=self.type, status=self.status)
341    
342     @property
343     def status(self):
344     return (self.exists and
345     self.__class__ is not DeviceFormat and
346     isinstance(self.device, str) and
347     self.device and
348     os.path.exists(self.device))
349    
350     @property
351     def formattable(self):
352     """ Can we create formats of this type? """
353     return self._formattable
354    
355     @property
356     def supported(self):
357     """ Is this format a supported type? """
358     return self._supported
359    
360     @property
361     def packages(self):
362     """ Packages required to manage formats of this type. """
363     return self._packages
364    
365     @property
366     def services(self):
367     """ Services required to manage formats of this type. """
368     return self._services
369    
370     @property
371     def resizable(self):
372     """ Can formats of this type be resized? """
373     return self._resizable and self.exists
374    
375     @property
376     def bootable(self):
377     """ Is this format type suitable for a boot partition? """
378     return self._bootable
379    
380     @property
381     def migratable(self):
382     """ Can formats of this type be migrated? """
383     return self._migratable
384    
385     @property
386     def migrate(self):
387     return self._migrate
388    
389     @property
390     def linuxNative(self):
391     """ Is this format type native to linux? """
392     return self._linuxNative
393    
394     @property
395     def mountable(self):
396     """ Is this something we can mount? """
397     return False
398    
399     @property
400     def dump(self):
401     """ Whether or not this format will be dumped by dump(8). """
402     return self._dump
403    
404     @property
405     def check(self):
406     """ Whether or not this format is checked on boot. """
407     return self._check
408    
409     @property
410     def maxSize(self):
411     """ Maximum size (in MB) for this format type. """
412     return self._maxSize
413    
414     @property
415     def minSize(self):
416     """ Minimum size (in MB) for this format type. """
417     return self._minSize
418    
419     @property
420     def hidden(self):
421     """ Whether devices with this formatting should be hidden in UIs. """
422     return self._hidden
423    
424     @property
425     def majorminor(self):
426     """A string suitable for using as a pseudo-unique ID in kickstart."""
427     if not self._majorminor:
428     # If this is a device-mapper device, we have to get the DM node and
429     # build the sysfs path from that.
430     try:
431     device = dm_node_from_name(self.device)
432     except DMError:
433     device = self.device
434    
435     try:
436     sysfs_path = get_sysfs_path_by_name(device)
437     except RuntimeError:
438     raise StorageError("DeviceFormat.majorminor: "
439     "can not get majorminor for '%s'" % device)
440    
441     dev = udev_get_device(sysfs_path[4:])
442     self._majorminor = "%03d%03d" %\
443     (udev_device_get_major(dev), udev_device_get_minor(dev))
444     return self._majorminor
445    
446     def writeKS(self, f):
447     return
448    
449     collect_device_format_classes()

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