# Copyright (c) 2015 SUSE Linux GmbH. All rights reserved.
#
# This file is part of kiwi.
#
# kiwi is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# kiwi 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with kiwi. If not, see <http://www.gnu.org/licenses/>
#
import os
import logging
from typing import Optional
# project
from kiwi.command import Command
from kiwi.storage.device_provider import DeviceProvider
from kiwi.storage.mapped_device import MappedDevice
from kiwi.exceptions import (
KiwiRaidSetupError
)
log = logging.getLogger('kiwi')
[docs]
class RaidDevice(DeviceProvider):
"""
**Implement raid setup on a storage device**
:param object storage_provider: Instance of class based on DeviceProvider
"""
def __init__(self, storage_provider: DeviceProvider):
#: the underlaying device provider
self.storage_provider = storage_provider
self.raid_level_map = {
'mirroring': '1',
'striping': '0'
}
self.raid_device = None
def __enter__(self):
return self
[docs]
def get_device(self) -> Optional[MappedDevice]:
"""
Instance of MappedDevice providing the raid device
:return: mapped raid device
:rtype: MappedDevice
"""
if self.raid_device:
return MappedDevice(
device=self.raid_device, device_provider=self
)
return None
[docs]
def create_degraded_raid(self, raid_level):
"""
Create a raid array in degraded mode with one device missing.
This only works in the raid levels 0(striping) and 1(mirroring)
:param string raid_level: raid level name
"""
if raid_level not in self.raid_level_map:
raise KiwiRaidSetupError(
'Only raid levels 0(striping) and 1(mirroring) are supported'
)
raid_device = None
for raid_id in range(9):
raid_device = '/dev/md' + format(raid_id)
if os.path.exists(raid_device):
raid_device = None
else:
break
if not raid_device:
raise KiwiRaidSetupError(
'Could not find free raid device in range md0-8'
)
log.info(
'Creating raid array in %s mode as %s',
raid_level, raid_device
)
Command.run(
[
'mdadm', '--create', '--run', raid_device,
'--level', self.raid_level_map[raid_level],
'--raid-disks', '2',
self.storage_provider.get_device(), 'missing'
]
)
self.raid_device = raid_device
[docs]
def create_raid_config(self, filename: str) -> None:
"""
Create mdadm config file from mdadm request
:param string filename: config file name
"""
if not self.raid_device:
raise KiwiRaidSetupError("No raid device defined, cannot create raid config!")
mdadm_call = Command.run(
['mdadm', '-Db', self.raid_device]
)
with open(filename, 'w') as mdadmconf:
mdadmconf.write(mdadm_call.output)
[docs]
def is_loop(self) -> bool:
"""
Check if storage provider is loop based
Return loop status from base storage provider
:return: True or False
:rtype: bool
"""
return self.storage_provider.is_loop()
def __exit__(self, exc_type, exc_value, traceback):
if self.raid_device:
try:
Command.run(
['mdadm', '--stop', self.raid_device]
)
except Exception as issue:
log.error(
'Shutdown of raid device {0} failed with: {1}'.format(
self.raid_device, issue
)
)