
Add possibility to skip cleaning of MD containers which are usually represent fake RAID devices. So, those devices won't be cleaned and removed at the partitioning step. That will effectively save those devices for further provisioning purposes. In order to preserve existing behavior, it will be disabled by default in conf file. Will be enabled in a separate patch. Change-Id: I7be1fc438ffe1fec9b8bfae7e47f50cd3a7c36b7 Related-Bug: #1508908
160 lines
5.2 KiB
Python
160 lines
5.2 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
# Copyright 2015 Mirantis, Inc.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
import copy
|
|
|
|
from fuel_agent.objects import base
|
|
from fuel_agent.openstack.common import log as logging
|
|
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
class Parted(base.Serializable):
|
|
|
|
def __init__(self, name, label, partitions=None, install_bootloader=False):
|
|
self.name = name
|
|
self.label = label
|
|
self.partitions = partitions or []
|
|
self.install_bootloader = install_bootloader
|
|
|
|
def add_partition(self, **kwargs):
|
|
# TODO(kozhukalov): validate before appending
|
|
# calculating partition name based on device name and partition count
|
|
kwargs['name'] = self.next_name()
|
|
kwargs['count'] = self.next_count()
|
|
kwargs['device'] = self.name
|
|
# if begin is given use its value else use end of last partition
|
|
kwargs['begin'] = kwargs.get('begin', self.next_begin())
|
|
# if end is given use its value else
|
|
# try to calculate it based on size kwarg or
|
|
# raise KeyError
|
|
# (kwargs.pop['size'] will raise error if size is not set)
|
|
kwargs['end'] = kwargs.get('end') or \
|
|
kwargs['begin'] + kwargs.pop('size')
|
|
# if partition_type is given use its value else
|
|
# try to calculate it automatically
|
|
kwargs['partition_type'] = \
|
|
kwargs.get('partition_type', self.next_type())
|
|
partition = Partition(**kwargs)
|
|
self.partitions.append(partition)
|
|
return partition
|
|
|
|
@property
|
|
def logical(self):
|
|
return [x for x in self.partitions if x.type == 'logical']
|
|
|
|
@property
|
|
def primary(self):
|
|
return [x for x in self.partitions if x.type == 'primary']
|
|
|
|
@property
|
|
def extended(self):
|
|
return next((x for x in self.partitions if x.type == 'extended'), None)
|
|
|
|
def next_type(self):
|
|
if self.label == 'gpt':
|
|
return 'primary'
|
|
elif self.label == 'msdos':
|
|
if self.extended:
|
|
return 'logical'
|
|
elif len(self.partitions) < 3 and not self.extended:
|
|
return 'primary'
|
|
elif len(self.partitions) == 3 and not self.extended:
|
|
return 'extended'
|
|
# NOTE(agordeev): how to reach that condition?
|
|
else:
|
|
return 'logical'
|
|
|
|
def next_count(self, next_type=None):
|
|
next_type = next_type or self.next_type()
|
|
if next_type == 'logical':
|
|
return len(self.logical) + 5
|
|
return len(self.partitions) + 1
|
|
|
|
def next_begin(self):
|
|
if not self.partitions:
|
|
return 1
|
|
if self.partitions[-1] == self.extended:
|
|
return self.partitions[-1].begin
|
|
return self.partitions[-1].end
|
|
|
|
def next_name(self):
|
|
if self.next_type() == 'extended':
|
|
return None
|
|
separator = ''
|
|
special_devices = ('cciss', 'nvme', 'loop', 'md')
|
|
if any(n in self.name for n in special_devices):
|
|
separator = 'p'
|
|
return '%s%s%s' % (self.name, separator, self.next_count())
|
|
|
|
def partition_by_name(self, name):
|
|
return next((x for x in self.partitions if x.name == name), None)
|
|
|
|
def to_dict(self):
|
|
partitions = [partition.to_dict() for partition in self.partitions]
|
|
return {
|
|
'name': self.name,
|
|
'label': self.label,
|
|
'partitions': partitions,
|
|
'install_bootloader': self.install_bootloader,
|
|
}
|
|
|
|
@classmethod
|
|
def from_dict(cls, data):
|
|
data = copy.deepcopy(data)
|
|
raw_partitions = data.pop('partitions')
|
|
partitions = [Partition.from_dict(partition)
|
|
for partition in raw_partitions]
|
|
return cls(partitions=partitions, **data)
|
|
|
|
|
|
class Partition(base.Serializable):
|
|
|
|
def __init__(self, name, count, device, begin, end, partition_type,
|
|
flags=None, guid=None, configdrive=False, keep_data=False):
|
|
self.keep_data = keep_data
|
|
self.name = name
|
|
self.count = count
|
|
self.device = device
|
|
self.begin = begin
|
|
self.end = end
|
|
self.type = partition_type
|
|
self.flags = flags or []
|
|
self.guid = guid
|
|
self.configdrive = configdrive
|
|
|
|
def set_flag(self, flag):
|
|
if flag not in self.flags:
|
|
self.flags.append(flag)
|
|
|
|
def set_guid(self, guid):
|
|
self.guid = guid
|
|
|
|
def to_dict(self):
|
|
return {
|
|
'name': self.name,
|
|
'count': self.count,
|
|
'device': self.device,
|
|
'begin': self.begin,
|
|
'end': self.end,
|
|
'partition_type': self.type,
|
|
'flags': self.flags,
|
|
'guid': self.guid,
|
|
'configdrive': self.configdrive,
|
|
'keep_data': self.keep_data,
|
|
}
|