# Copyright (C) 2012 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 ExtentProvider class.
ExtentProvider
--------------
.. autoclass:: ExtentProvider
:members:
"""
from openlmi.storage.DeviceProvider import DeviceProvider
import pywbem
import blivet.formats
import openlmi.storage.util.storage as storage
import openlmi.common.cmpi_logging as cmpi_logging
[docs]class ExtentProvider(DeviceProvider):
"""
Base of all StorageExtent providers.
It fills common properties in the StorageExtent.
"""
@cmpi_logging.trace_method
[docs] def __init__(self, classname, *args, **kwargs):
self.classname = classname
super(ExtentProvider, self).__init__(*args, **kwargs)
@cmpi_logging.trace_method
def _get_device(self, object_name):
"""
Get Anaconda StorageDevice for given name, without any checks.
"""
path = object_name['DeviceID']
device = storage.get_device_for_persistent_name(self.storage, path)
return device
@cmpi_logging.trace_method
[docs] def provides_name(self, object_name):
"""
Returns True, if this class is provider for given CIM InstanceName.
"""
if not (object_name.has_key('SystemName')
and object_name.has_key('SystemCreationClassName')
and object_name.has_key('CreationClassName')
and object_name.has_key('DeviceID')):
return False
if object_name['SystemName'] != self.config.system_name:
return False
if object_name['SystemCreationClassName'] != \
self.config.system_class_name:
return False
if object_name['CreationClassName'] != self.classname:
return False
return True
@cmpi_logging.trace_method
[docs] def get_device_for_name(self, object_name):
"""
Returns Anaconda StorageDevice for given CIM InstanceName or
None if no device is found.
"""
if self.provides_name(object_name):
return self._get_device(object_name)
@cmpi_logging.trace_method
[docs] def get_name_for_device(self, device):
"""
Returns CIM InstanceName for given Anaconda StorageDevice.
None if no device is found.
"""
name = pywbem.CIMInstanceName(self.classname,
namespace=self.config.namespace,
keybindings={
'SystemName' : self.config.system_name,
'SystemCreationClassName' : self.config.system_class_name,
'CreationClassName' : self.classname,
'DeviceID': storage.get_persistent_name(device)
})
return name
@cmpi_logging.trace_method
[docs] def get_element_name(self, device):
"""
Return ElementName property value for given StorageDevice.
Device path (/dev/sda) is the default.
"""
return device.name
@cmpi_logging.trace_method
# pylint: disable-msg=W0613
[docs] def get_extent_status(self, device):
"""
Return ExtentStatus property value for given StorageDevice.
It must be array of int16 values.
"""
return []
@cmpi_logging.trace_method
[docs] def get_size(self, device):
"""
Return (BlockSize, NumberOfBlocks, ConsumableBlocks) properties
for given StorageDevice.
The ConsumableBlocks should be reduced by partition table size.
"""
if device.partedDevice:
block_size = pywbem.Uint64(device.partedDevice.sectorSize)
total_blocks = device.partedDevice.length
consumable_blocks = device.partedDevice.length
if (device.format and isinstance(device.format,
blivet.formats.disklabel.DiskLabel)):
# reduce by partition table size
consumable_blocks -= storage.get_partition_table_size(
device)
else:
block_size = None
total_blocks = None
consumable_blocks = None
return (block_size, total_blocks, consumable_blocks)
@cmpi_logging.trace_method
# pylint: disable-msg=W0613
[docs] def get_primordial(self, device):
"""
Returns True, if given StorageDevice is primordial.
"""
if isinstance(device, blivet.devices.DiskDevice):
return True
else:
return False
@cmpi_logging.trace_method
[docs] def get_discriminator(self, device):
"""
Returns ExtentDiscriminator property value for given StorageDevice.
It must return array of strings.
"""
discriminator = []
if device.format and isinstance(device.format,
blivet.formats.lvmpv.LVMPhysicalVolume):
discriminator.append(self.Values.Discriminator.Pool_Component)
return discriminator
@cmpi_logging.trace_method
[docs] def get_names(self, device):
"""
Return array of all aliases (symlinks) of the device. The real
device path is always the first element of the array.
:param device: (``StorageDevice``) The device.
:returns: ``array of strings``.
"""
return [device.path] + device.deviceLinks
@cmpi_logging.trace_method
# pylint: disable-msg=W0221
[docs] def get_instance(self, env, model, device=None):
"""
Provider implementation of GetInstance intrinsic method.
It fills common StorageExtent properties.
"""
if not self.provides_name(model):
raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, "Wrong keys.")
if not device:
device = self._get_device(model)
if not device:
raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND,
"Cannot find the extent.")
model['ElementName'] = self.get_element_name(device)
model['NameNamespace'] = self.Values.NameNamespace.OS_Device_Namespace
model['NameFormat'] = self.Values.NameFormat.OS_Device_Name
model['Name'] = device.path
extent_status = self.get_extent_status(device)
model['ExtentStatus'] = pywbem.CIMProperty(
name='ExtentStatus',
value=extent_status,
type='uint16',
array_size=len(extent_status),
is_array=True)
operational_status = self.get_status(device)
model['OperationalStatus'] = pywbem.CIMProperty(
name='OperationalStatus',
value=operational_status,
type='uint16',
array_size=len(operational_status),
is_array=True)
(block_size, total_blocks, consumable_blocks) = self.get_size(device)
if block_size:
model['BlockSize'] = pywbem.Uint64(block_size)
if total_blocks:
model['NumberOfBlocks'] = pywbem.Uint64(total_blocks)
if consumable_blocks:
model['ConsumableBlocks'] = pywbem.Uint64(consumable_blocks)
redundancy = self.get_redundancy(device)
model['NoSinglePointOfFailure'] = redundancy.no_single_point_of_failure
model['DataRedundancy'] = pywbem.Uint16(redundancy.data_redundancy)
model['PackageRedundancy'] = pywbem.Uint16(
redundancy.package_redundancy)
model['ExtentStripeLength'] = pywbem.Uint64(redundancy.stripe_length)
model['IsComposite'] = (len(device.parents) > 1)
# TODO: add DeltaReservation (mandatory in SMI-S)
model['Primordial'] = self.get_primordial(device)
model['Names'] = self.get_names(device)
discriminator = self.get_discriminator(device)
model['ExtentDiscriminator'] = pywbem.CIMProperty(
name='ExtentDiscriminator',
value=discriminator,
type='string',
array_size=len(discriminator),
is_array=True)
return model
@cmpi_logging.trace_method
[docs] def enumerate_devices(self):
"""
Enumerate all StorageDevices, that this provider provides.
"""
pass
@cmpi_logging.trace_method
[docs] def enum_instances(self, env, model, keys_only):
"""Enumerate instances.
The WBEM operations EnumerateInstances and EnumerateInstanceNames
are both mapped to this method.
This method is a python generator
Keyword arguments:
env -- Provider Environment (pycimmb.ProviderEnvironment)
model -- A template of the pywbem.CIMInstances to be generated.
The properties of the model are already filtered according to
the PropertyList from the request. Only properties present in
the model need to be given values. If you prefer, you can
always set all of the values, and the instance will be filtered
for you.
keys_only -- A boolean. True if only the key properties should be
set on the generated instances.
Possible Errors:
CIM_ERR_FAILED (some other unspecified error occurred)
"""
model.path.update({'CreationClassName': None, 'SystemName': None,
'DeviceID': None, 'SystemCreationClassName': None})
for device in self.enumerate_devices():
name = self.get_name_for_device(device)
model['SystemName'] = name['SystemName']
model['SystemCreationClassName'] = name['SystemCreationClassName']
model['CreationClassName'] = name['CreationClassName']
model['DeviceID'] = name['DeviceID']
if keys_only:
yield model
else:
yield self.get_instance(env, model, device)
class Values(DeviceProvider.Values):
class NameNamespace(object):
Unknown = pywbem.Uint16(0)
Other = pywbem.Uint16(1)
VPD83Type3 = pywbem.Uint16(2)
VPD83Type2 = pywbem.Uint16(3)
VPD83Type1 = pywbem.Uint16(4)
VPD80 = pywbem.Uint16(5)
NodeWWN = pywbem.Uint16(6)
SNVM = pywbem.Uint16(7)
OS_Device_Namespace = pywbem.Uint16(8)
class NameFormat(object):
Unknown = pywbem.Uint16(0)
Other = pywbem.Uint16(1)
VPD83NAA6 = pywbem.Uint16(2)
VPD83NAA5 = pywbem.Uint16(3)
VPD83Type2 = pywbem.Uint16(4)
VPD83Type1 = pywbem.Uint16(5)
VPD83Type0 = pywbem.Uint16(6)
SNVM = pywbem.Uint16(7)
NodeWWN = pywbem.Uint16(8)
NAA = pywbem.Uint16(9)
EUI64 = pywbem.Uint16(10)
T10VID = pywbem.Uint16(11)
OS_Device_Name = pywbem.Uint16(12)
class ExtentStatus(object):
Other = pywbem.Uint16(0)
Unknown = pywbem.Uint16(1)
None_Not_Applicable = pywbem.Uint16(2)
Broken = pywbem.Uint16(3)
Data_Lost = pywbem.Uint16(4)
Dynamic_Reconfig = pywbem.Uint16(5)
Exposed = pywbem.Uint16(6)
Fractionally_Exposed = pywbem.Uint16(7)
Partially_Exposed = pywbem.Uint16(8)
Protection_Disabled = pywbem.Uint16(9)
Readying = pywbem.Uint16(10)
Rebuild = pywbem.Uint16(11)
Recalculate = pywbem.Uint16(12)
Spare_in_Use = pywbem.Uint16(13)
Verify_In_Progress = pywbem.Uint16(14)
In_Band_Access_Granted = pywbem.Uint16(15)
Imported = pywbem.Uint16(16)
Exported = pywbem.Uint16(17)
Relocating = pywbem.Uint16(18)
# DMTF_Reserved = ..
class Usage(object):
Other = pywbem.Uint16(1)
Unrestricted = pywbem.Uint16(2)
Reserved_for_ComputerSystem__the_block_server_ = pywbem.Uint16(3)
Reserved_by_Replication_Services = pywbem.Uint16(4)
Reserved_by_Migration_Services = pywbem.Uint16(5)
Local_Replica_Source = pywbem.Uint16(6)
Remote_Replica_Source = pywbem.Uint16(7)
Local_Replica_Target = pywbem.Uint16(8)
Remote_Replica_Target = pywbem.Uint16(9)
Local_Replica_Source_or_Target = pywbem.Uint16(10)
Remote_Replica_Source_or_Target = pywbem.Uint16(11)
Delta_Replica_Target = pywbem.Uint16(12)
Element_Component = pywbem.Uint16(13)
Reserved_as_Pool_Contributor = pywbem.Uint16(14)
Composite_Volume_Member = pywbem.Uint16(15)
Composite_LogicalDisk_Member = pywbem.Uint16(16)
Reserved_for_Sparing = pywbem.Uint16(17)
# DMTF_Reserved = ..
# Vendor_Reserved = 32768..65535
class Discriminator(object):
Pool_Component = 'SNIA:PoolComponent'
Composite = 'SNIA:Composite'
Imported = 'SNIA:Imported'
Allocated = 'SNIA:Allocated'