Source code for openlmi.storage.LMI_DiskPartitionConfigurationCapabilities

# 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 LMI_DiskPartitionConfigurationCapabilities class.

LMI_DiskPartitionConfigurationCapabilities
------------------------------------------

.. autoclass:: LMI_DiskPartitionConfigurationCapabilities
    :members:

"""

from openlmi.storage.CapabilitiesProvider import CapabilitiesProvider
from openlmi.storage.LMI_DiskPartitionConfigurationSetting \
        import LMI_DiskPartitionConfigurationSetting
from openlmi.storage.SettingManager import Setting
import pywbem
import blivet.formats
import parted
import openlmi.common.cmpi_logging as cmpi_logging
import openlmi.storage.util.units as units

[docs]class LMI_DiskPartitionConfigurationCapabilities(CapabilitiesProvider): """ LMI_DiskPartitionConfigurationCapabilities provider implementation. """ INSTANCE_ID_MBR = "LMI:LMI_DiskPartitionConfigurationCapabilities:MBR" INSTANCE_ID_EMBR = "LMI:LMI_DiskPartitionConfigurationCapabilities:EMBR" INSTANCE_ID_GPT = "LMI:LMI_DiskPartitionConfigurationCapabilities:GPT" @cmpi_logging.trace_method
[docs] def __init__(self, *args, **kwargs): super(LMI_DiskPartitionConfigurationCapabilities, self).__init__( "LMI_DiskPartitionConfigurationCapabilities", *args, **kwargs) sync_actions = self.Values.SupportedSynchronousActions self.instances = [ { 'InstanceID': self.INSTANCE_ID_MBR, 'SupportedSettings': [ self.Values.SupportedSettings.Partition_Type, self.Values.SupportedSettings.Bootable], 'PartitionTableSize': pywbem.Uint32(1), 'PartitionStyle': self.Values.PartitionStyle.MBR, 'ValidSubPartitionStyles': [ self.Values.ValidSubPartitionStyles.EMBR], 'MaxNumberOfPartitions': pywbem.Uint16(4), 'SupportedSynchronousActions': [ sync_actions.CreateOrModifyPartition, sync_actions.SetPartitionStyle], 'Caption': "Capabilities of MSDOS style primary " \ "partitions.", 'MaxCapacity': pywbem.Uint64(units.MAXINT64), 'ElementName': 'MBRCapabilities', 'OverlapAllowed' : False, # TODO: add Hidden flag? It seems it does not work # on MBR partitions }, { 'InstanceID': self.INSTANCE_ID_EMBR, 'SupportedSettings': [ self.Values.SupportedSettings.Bootable], 'PartitionTableSize': pywbem.Uint32(1), 'PartitionStyle': self.Values.PartitionStyle.EMBR, 'ValidSubPartitionStyles': pywbem.CIMProperty( name='ValidSubPartitionStyles', value=None, type='uint16', array_size=0, is_array=True), 'MaxNumberOfPartitions': pywbem.Uint16(2 << 15 - 1), 'SupportedSynchronousActions': [ sync_actions.CreateOrModifyPartition, sync_actions.SetPartitionStyle], 'Caption': "Capabilities of MS-DOS style logical partitions.", 'MaxCapacity': pywbem.Uint64(units.MAXINT64), 'ElementName': 'EMBRCapabilities', 'OverlapAllowed' : False, }, { 'InstanceID': self.INSTANCE_ID_GPT, 'SupportedSettings': [ self.Values.SupportedSettings.Bootable, ], 'PartitionTableSize': pywbem.Uint32(68), 'PartitionStyle': self.Values.PartitionStyle.GPT, 'ValidSubPartitionStyles': pywbem.CIMProperty( name='ValidSubPartitionStyles', value=None, type='uint16', array_size=0, is_array=True), 'MaxNumberOfPartitions': pywbem.Uint16(128), 'SupportedSynchronousActions': [ sync_actions.CreateOrModifyPartition, sync_actions.SetPartitionStyle], 'Caption': "Capabilities of GPT partitions.", 'MaxCapacity': pywbem.Uint64(units.MAXINT64), 'ElementName': 'GPTCapabilities', 'OverlapAllowed' : False, CapabilitiesProvider.DEFAULT_CAPABILITY: True, }, ]
@cmpi_logging.trace_method
[docs] def enumerate_capabilities(self): """ Return an iterable with all capabilities instances, i.e. dictionaries property_name -> value. If the capabilities are the default ones, it must have '_default' as a property name. """ return self.instances
@cmpi_logging.trace_method
[docs] def create_setting_for_capabilities(self, capabilities): """ Create LMI_*Setting for given capabilities. Return CIMInstanceName of the setting or raise CIMError on error. """ setting_id = self.setting_manager.allocate_id( 'LMI_DiskPartitionConfigurationSetting') if not setting_id: raise pywbem.CIMError(pywbem.CIM_ERR_FAILED, "Failed to allocate setting InstanceID") values = LMI_DiskPartitionConfigurationSetting.Values setting = self.setting_manager.create_setting( 'LMI_DiskPartitionConfigurationSetting', Setting.TYPE_TRANSIENT, setting_id) setting['Bootable'] = False setting['ElementName'] = 'CreatedFrom' + capabilities['InstanceID'] setting['Hidden'] = None if (capabilities['PartitionStyle'] == self.Values.PartitionStyle.GPT or capabilities['PartitionStyle'] == self.Values.PartitionStyle.MBR): setting['PartitionType'] = values.PartitionType.Primary else: setting['PartitionType'] = values.PartitionType.Logical self.setting_manager.set_setting( 'LMI_DiskPartitionConfigurationSetting', setting) return pywbem.CIMInstanceName( classname='LMI_DiskPartitionConfigurationSetting', namespace=self.config.namespace, keybindings={'InstanceID': setting_id})
@cmpi_logging.trace_method
[docs] def cim_method_getalignment(self, env, object_name, param_extent=None): """ Implements LMI_DiskPartitionConfigurationCapabilities.GetAlignment() Return allignment unit for given StorageExtent (in blocks). New partitions and metadata sectors should be aligned to this unit. """ capabilities = self.get_capabilities_for_id(object_name['InstanceID']) if not capabilities: raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, "Capabilities not found.") if not param_extent: raise pywbem.CIMError(pywbem.CIM_ERR_INVALID_PARAMETER, "Parameter Extent must be provided.") device = self.provider_manager.get_device_for_name(param_extent) if not device: raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, "Extent not found.") self.check_capabilities_for_device(device, capabilities) if capabilities['PartitionStyle'] == self.Values.PartitionStyle.EMBR: device = device.parents[0] alignment = device.partedDevice.optimumAlignment.grainSize out_params = [pywbem.CIMParameter('alignment', type='uint64', value=pywbem.Uint64(alignment))] retval = self.Values.GetAlignment.Success return (retval, out_params)
@cmpi_logging.trace_method
[docs] def get_capabilities_for_device(self, device): """ Return capabilities for given StorageDevice Return None if it does not have any partition capabilities. """ if isinstance(device, blivet.devices.PartitionDevice): if device.isExtended: return self.get_capabilities_for_id(self.INSTANCE_ID_EMBR) return None fmt_class = blivet.formats.disklabel.DiskLabel if (not device.format) or (not isinstance(device.format, fmt_class)): return None if device.format.labelType == "msdos": return self.get_capabilities_for_id(self.INSTANCE_ID_MBR) if device.format.labelType == "gpt": return self.get_capabilities_for_id(self.INSTANCE_ID_GPT)
@cmpi_logging.trace_method
[docs] def check_capabilities_for_device(self, device, capabilities): """ Check if the capabilities are the right one for the device and raise exception if something is wrong. """ if capabilities['PartitionStyle'] == self.Values.PartitionStyle.MBR: if (not device.format or not isinstance( device.format, blivet.formats.disklabel.DiskLabel)): raise pywbem.CIMError(pywbem.CIM_ERR_INVALID_PARAMETER, "There is no partition table on the Extent.") if device.format.labelType != "msdos": raise pywbem.CIMError(pywbem.CIM_ERR_INVALID_PARAMETER, "Partition table does not have given Capabilities.") elif capabilities['PartitionStyle'] == self.Values.PartitionStyle.GPT: if (not device.format or not isinstance( device.format, blivet.formats.disklabel.DiskLabel)): raise pywbem.CIMError(pywbem.CIM_ERR_INVALID_PARAMETER, "There is no partition table on the Extent.") if device.format.labelType != "gpt": raise pywbem.CIMError(pywbem.CIM_ERR_INVALID_PARAMETER, "Partition table does not have given Capabilities.") else: # the device must be extended partition, find its disk if not isinstance( device, blivet.devices.PartitionDevice): raise pywbem.CIMError(pywbem.CIM_ERR_INVALID_PARAMETER, "The extent is not an partition.") if not device.isExtended: raise pywbem.CIMError(pywbem.CIM_ERR_INVALID_PARAMETER, "The extent is not an extended partition.") return True
@cmpi_logging.trace_method
[docs] def cim_method_findpartitionlocation(self, env, object_name, param_extent=None, param_size=None): """ Implements LMI_DiskPartitionConfigurationCapabilities .FindPartitionLocation() This method finds the best place for partition of given size. """ capabilities = self.get_capabilities_for_id(object_name['InstanceID']) if not capabilities: raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, "Capabilities not found.") # Check parameters if not param_extent: raise pywbem.CIMError(pywbem.CIM_ERR_INVALID_PARAMETER, "Parameter Extent must be provided.") device = self.provider_manager.get_device_for_name(param_extent) if not device: raise pywbem.CIMError(pywbem.CIM_ERR_NOT_FOUND, "Extent not found.") # Check device vs capabilities self.check_capabilities_for_device(device, capabilities) if capabilities['PartitionStyle'] == self.Values.PartitionStyle.EMBR: device = device.parents[0] part_type = parted.PARTITION_LOGICAL else: part_type = parted.PARTITION_NORMAL if not param_size: grow = True size = 1.0 else: grow = False size = param_size / (units.MEGABYTE * 1.0) # Find the best place geometry = blivet.partitioning.getBestFreeSpaceRegion( disk=device.format.partedDisk, part_type=part_type, req_size=size, grow=grow) if not geometry: # No place found retval = self.Values.FindPartitionLocation.Not_Enough_Free_Space out_params = [pywbem.CIMParameter('size', type='uint64', value=pywbem.Uint64(0))] return (retval, out_params) retval = self.Values.FindPartitionLocation.Success sector_size = device.partedDevice.sectorSize new_size = geometry.length * device.partedDevice.sectorSize # anaconda returns the whole region size, we should make it smaller # to adjust to requested size if not grow and new_size > param_size: # truncate the end to start + size geometry.end = geometry.start + (param_size / sector_size) if param_size % sector_size > 0: geometry.end = geometry.end + 1 new_size = (geometry.end - geometry.start) * sector_size out_params = [pywbem.CIMParameter('size', type='uint64', value=pywbem.Uint64(new_size))] out_params += [pywbem.CIMParameter('startingaddress', type='uint64', value=pywbem.Uint64(geometry.start))] out_params += [pywbem.CIMParameter('endingaddress', type='uint64', value=pywbem.Uint64(geometry.end))] return (retval, out_params)
class Values(CapabilitiesProvider.Values): class SupportedSettings(object): Partition_Type = pywbem.Uint16(1) Bootable = pywbem.Uint16(2) Hidden = pywbem.Uint16(3) class ValidSubPartitionStyles(object): Other = pywbem.Uint16(1) MBR = pywbem.Uint16(2) VTOC = pywbem.Uint16(3) GPT = pywbem.Uint16(4) EMBR = pywbem.Uint16(4100) class SupportedSynchronousActions(object): SetPartitionStyle = pywbem.Uint16(2) CreateOrModifyPartition = pywbem.Uint16(3) # DMTF_Reserved = .. # Vendor_Reserved = 0x8000.. class PartitionStyle(object): MBR = pywbem.Uint16(2) GPT = pywbem.Uint16(3) VTOC = pywbem.Uint16(4) PC98 = pywbem.Uint16(4097) SUN = pywbem.Uint16(4098) MAC = pywbem.Uint16(4099) EMBR = pywbem.Uint16(4100) class GetAlignment(object): Success = pywbem.Uint32(0) Not_Supported = pywbem.Uint32(1) Failed = pywbem.Uint32(4) class FindPartitionLocation(object): Success = pywbem.Uint32(0) Not_Supported = pywbem.Uint32(1) Failed = pywbem.Uint32(4) Not_Enough_Free_Space = pywbem.Uint32(100)