
Python 3.4 env is added to tox config file oslo.serialization is pinned to version smaller than 2.0 test_calculate_md5_ok had to be rewritten due to bug in mock_open in unittest.mock library in python 3.4: https://bugs.python.org/issue23004 Change-Id: Idf2fa15ff4035b9fe92027acdcaf51e005b52541 Implements blueprint: volume-manager-refactoring
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')
|
|
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,
|
|
}
|