# Copyright (C) 2013 Red Hat, Inc. All rights reserved.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
# Authors: Jan Safranek <jsafrane@redhat.com>
# -*- coding: utf-8 -*-
""""
Module for FormatProvider.
FormatProvider
--------------
.. autoclass:: FormatProvider
:members:
LMI_ResidesOnExtent
-------------------
.. autoclass:: LMI_ResidesOnExtent
:members:
"""
import pywbem
from openlmi.storage.BaseProvider import BaseProvider
import openlmi.common.cmpi_logging as cmpi_logging
from openlmi.storage.util import storage
[docs]class FormatProvider(BaseProvider):
"""
Abstract provider for data formats and filesystems.
Each provider must have .device_type property, which represents
blivet.formats.<DeviceFormat child>.type of format it
represents.
"""
@cmpi_logging.trace_method
[docs] def __init__(self, classname, device_type, *args, **kwargs):
self.classname = classname
self.device_type = device_type
super(FormatProvider, self).__init__(*args, **kwargs)
@cmpi_logging.trace_method
# pylint: disable-msg=W0613
[docs] def provides_name(self, name):
"""
Returns True, if this class is provider for given CIMInstanceName.
Subclasses do not need to override this method as long as
self.classname is correct CIM class name.
"""
if not (name.has_key("CSCreationClassName")
and name.has_key("CSName")
and name.has_key("CreationClassName")
and name.has_key("Name")):
return False
if name['CreationClassName'] != self.classname:
return False
if name['CSCreationClassName'] != self.config.system_class_name:
return False
if name['CSName'] != self.config.system_name:
return False
return True
@cmpi_logging.trace_method
# pylint: disable-msg=W0613
[docs] def provides_format(self, device, fmt):
"""
Returns True, if this class is provider for given Anaconda
DeviceFormat class.
Subclasses must override this method.
"""
return False
@cmpi_logging.trace_method
[docs] def get_uuid(self, device, fmt):
"""
Return UUID of the format or None when it does not exist.
"""
try:
return fmt.uuid
except AttributeError:
return None
@cmpi_logging.trace_method
[docs] def get_format_id(self, device, fmt):
"""
Return LMI_DataFormat.Name. The name should be unique and stable
across reboots or reconfigurations. UUID is used, subclasses
do not need to override this method.
"""
uuid = self.get_uuid(device, fmt)
if uuid:
return "UUID=" + uuid
return "DEVICE=" + storage.get_persistent_name(device)
@cmpi_logging.trace_method
[docs] def get_format_for_id(self, name):
"""
Return tuple (StorageDevice, DeviceFormat) for given Name property
of CIMInstance. Return (None, None) if no such format exist.
This is reverse function to get_format_id().
Subclasses do not need to override this method if they do not
override get_format_id().
The returned device represents one randomly chosen device if the
format spans over multiple devices, use get_devices() to get all
of them.
"""
if name.startswith("DEVICE="):
(_unused, devname) = name.split("=")
device = storage.get_device_for_persistent_name(self.storage, devname)
elif name.startswith("UUID="):
(_unused, uuid) = name.split("=")
device = self.storage.devicetree.getDeviceByUuid(uuid)
else:
return (None, None)
if not device:
return (None, None)
return (device, device.format)
@cmpi_logging.trace_method
[docs] def get_name_for_format(self, device, fmt):
""" Return CIMInstanceName for given DeviceFormat subclass."""
name = pywbem.CIMInstanceName(self.classname,
namespace=self.config.namespace,
keybindings={
"CSCreationClassName": self.config.system_class_name,
"CSName": self.config.system_name,
"CreationClassName": self.classname,
"Name": self.get_format_id(device, fmt)})
return name
@cmpi_logging.trace_method
[docs] def enum_instances(self, env, model, keys_only):
"""
Enumerate instances. Subclasses do not need to override this method,
as long as enumeration by self.provides_format is sufficient.
"""
model.path.update({'CSName': None, 'CreationClassName': None,
'CSCreationClassName': None, 'Name': None})
for device in self.storage.devices:
fmt = device.format
if fmt and self.provides_format(device, fmt):
name = self.get_name_for_format(device, fmt)
model.update(name)
if keys_only:
yield model
else:
yield self.get_instance(env, model, fmt)
@cmpi_logging.trace_method
[docs] def get_format_for_name(self, instance_name):
"""
Return tuple (StorageDevice, DeviceFormat) instance for given
CIMInstanceName. Return (None, None) if no such instance_name
exists.
The returned device represents one randomly chosen device if the
format spans over multiple devices, use get_devices() to get all
of them.
"""
if instance_name['CSName'] != self.config.system_name:
return (None, None)
if instance_name['CSCreationClassName'] != \
self.config.system_class_name:
return (None, None)
if instance_name['CreationClassName'] != self.classname:
return (None, None)
return self.get_format_for_id(instance_name['Name'])
@cmpi_logging.trace_method
# pylint: disable-msg=W0221
[docs] def get_instance(self, env, model, fmt=None):
"""
Get instance.
Subclasses should override this method, the default implementation
just check if the instance exists.
"""
if not fmt:
(device, fmt) = self.get_format_for_name(model)
if not fmt:
raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND,
"Cannot find the format.")
model['FormatTypeDescription'] = fmt.name
fmt_types = {
"swap": self.Values.FormatType.Swap,
"mdmember": self.Values.FormatType.MD_RAID_member,
"lvmpv": self.Values.FormatType.Physical_Volume,
"luks": self.Values.FormatType.LUKS,
"biosboot": self.Values.FormatType.BIOS_Boot,
"dmraidmember": self.Values.FormatType.DM_RAID_member,
"multipath_member": self.Values.FormatType.Multipath_member,
"prepboot": self.Values.FormatType.PPC_PReP_Boot,
}
fmt_type = fmt_types.get(fmt.type, self.Values.FormatType.Other)
model['FormatType'] = fmt_type
model['ElementName'] = fmt.device
return model
[docs] def get_devices(self, device, _fmt):
"""
Return all devices, on which the format resides.
Usually there is only one device, but btrfs may provide more.
"""
return [device]
class Values(object):
class FormatType(object):
Swap = pywbem.Uint16(1)
MD_RAID_member = pywbem.Uint16(2)
Physical_Volume = pywbem.Uint16(3)
LUKS = pywbem.Uint16(4)
BIOS_Boot = pywbem.Uint16(5)
DM_RAID_member = pywbem.Uint16(6)
Multipath_member = pywbem.Uint16(7)
PPC_PReP_Boot = pywbem.Uint16(8)
Other = pywbem.Uint16(65535)
[docs]class LMI_ResidesOnExtent(BaseProvider):
""" Implementation of LMI_ResidesOnExtent association."""
[docs] def __init__(self, *args, **kwargs):
super(LMI_ResidesOnExtent, self).__init__(*args, **kwargs)
@cmpi_logging.trace_method
[docs] def enum_instances(self, env, model, keys_only):
"""
Enumerate instances.
"""
model.path.update({'Dependent': None, 'Antecedent': None})
for device in self.storage.devices:
fmt = device.format
if not fmt or not fmt.type:
continue
provider = self.provider_manager.get_provider_for_format(
device, fmt)
if not provider:
continue
fmtname = provider.get_name_for_format(device, fmt)
devices = provider.get_devices(device, fmt)
for device in devices:
devname = self.provider_manager.get_name_for_device(device)
if not devname:
continue
model['Dependent'] = fmtname
model['Antecedent'] = devname
yield model
@cmpi_logging.trace_method
[docs] def get_instance(self, env, model):
""" Get instance. """
fmtname = model['Dependent']
devname = model['Antecedent']
# just check that the device has the format
device = self.provider_manager.get_device_for_name(devname)
if not device:
raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND,
"Cannot find Antecedent device.")
fmtprovider = self.provider_manager.get_provider_for_format_name(
fmtname)
if not fmtprovider:
raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND,
"The Antecedent device has unknown format.")
(device, fmt) = fmtprovider.get_format_for_name(fmtname)
if not fmt:
raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND,
"The Antecedent device has unknown format.")
fmt_devices = fmtprovider.get_devices(device, fmt)
if device not in fmt_devices:
raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND,
"The Antecedent device has different format.")
return model
@cmpi_logging.trace_method
[docs] def references(self, env, object_name, model, result_class_name, role,
result_role, keys_only):
"""Instrument Associations."""
# don't forget to try both DataFormat and LocalFileSystem subclasses!
refs = self.simple_references(
env, object_name, model,
result_class_name, role, result_role, keys_only,
"LMI_DataFormat",
"CIM_StorageExtent")
if refs:
return refs
refs = self.simple_references(
env, object_name, model,
result_class_name, role, result_role, keys_only,
"LMI_LocalFileSystem",
"CIM_StorageExtent")
return refs