Merge pull request #30 from CanonicalLtd/drop_pyparted
Drop python3-parted use
This commit is contained in:
commit
8ab7e2dd0f
2
Makefile
2
Makefile
|
@ -27,7 +27,7 @@ $(NAME)_$(VERSION).orig.tar.gz: clean
|
||||||
tarball: $(NAME)_$(VERSION).orig.tar.gz
|
tarball: $(NAME)_$(VERSION).orig.tar.gz
|
||||||
|
|
||||||
install_deps:
|
install_deps:
|
||||||
sudo apt-get install python3-urwid python3-pyudev python3-netifaces python3-nose python3-flake8 python3-parted python3-yaml git bzr ubuntu-cloudimage-keyring python3-jinja2 python3-coverage
|
sudo apt-get install python3-urwid python3-pyudev python3-netifaces python3-nose python3-flake8 python3-yaml git bzr ubuntu-cloudimage-keyring python3-jinja2 python3-coverage
|
||||||
|
|
||||||
dryrun:
|
dryrun:
|
||||||
$(MAKE) ui-view DRYRUN="--dry-run"
|
$(MAKE) ui-view DRYRUN="--dry-run"
|
||||||
|
|
|
@ -35,7 +35,6 @@ SRC_DEPS=(
|
||||||
)
|
)
|
||||||
INSTALLER_DEPS=(
|
INSTALLER_DEPS=(
|
||||||
"petname"
|
"petname"
|
||||||
"python3-parted"
|
|
||||||
"python3-urwid"
|
"python3-urwid"
|
||||||
"python3-pyudev"
|
"python3-pyudev"
|
||||||
"python3-netifaces"
|
"python3-netifaces"
|
||||||
|
|
|
@ -106,6 +106,7 @@ class FilesystemController(ControllerPolicy):
|
||||||
# adjust downward the partition size to accommodate
|
# adjust downward the partition size to accommodate
|
||||||
# the bios/grub partition
|
# the bios/grub partition
|
||||||
spec['bytes'] -= BIOS_GRUB_SIZE_BYTES
|
spec['bytes'] -= BIOS_GRUB_SIZE_BYTES
|
||||||
|
spec['partnum'] = 2
|
||||||
|
|
||||||
if spec["fstype"] in ["swap"]:
|
if spec["fstype"] in ["swap"]:
|
||||||
current_disk.add_partition(partnum=spec["partnum"],
|
current_disk.add_partition(partnum=spec["partnum"],
|
||||||
|
|
|
@ -17,12 +17,13 @@ import yaml
|
||||||
|
|
||||||
|
|
||||||
class DiskAction():
|
class DiskAction():
|
||||||
def __init__(self, action_id, model, serial, ptable='gpt'):
|
def __init__(self, action_id, model, serial, ptable='gpt', wipe=None):
|
||||||
self._action_id = action_id
|
self._action_id = action_id
|
||||||
self.parent = None
|
self.parent = None
|
||||||
self._ptable = ptable
|
self._ptable = ptable
|
||||||
self._model = model
|
self._model = model
|
||||||
self._serial = serial
|
self._serial = serial
|
||||||
|
self._wipe = wipe
|
||||||
|
|
||||||
def get_parent(self):
|
def get_parent(self):
|
||||||
return self.parent
|
return self.parent
|
||||||
|
@ -32,42 +33,55 @@ class DiskAction():
|
||||||
return str(self._action_id)
|
return str(self._action_id)
|
||||||
|
|
||||||
def get(self):
|
def get(self):
|
||||||
return {
|
action = {
|
||||||
'id': self.action_id,
|
'id': self.action_id,
|
||||||
'model': self._model,
|
'model': self._model,
|
||||||
'ptable': self._ptable,
|
'ptable': self._ptable,
|
||||||
'serial': self._serial,
|
'serial': self._serial,
|
||||||
'type': 'disk',
|
'type': 'disk',
|
||||||
}
|
}
|
||||||
|
if self._wipe:
|
||||||
|
action.update({'wipe': self._wipe})
|
||||||
|
return action
|
||||||
|
|
||||||
def dump(self):
|
def dump(self):
|
||||||
return yaml.dump(self.get(), default_flow_style=False)
|
return yaml.dump(self.get(), default_flow_style=False)
|
||||||
|
|
||||||
|
|
||||||
class PartitionAction(DiskAction):
|
class PartitionAction(DiskAction):
|
||||||
def __init__(self, parent, partnumber, size, flags=None):
|
def __init__(self, parent, partnum, offset, size, flags=None):
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
self.partnumber = int(partnumber)
|
self.partnum = int(partnum)
|
||||||
|
self._offset = int(offset)
|
||||||
self._size = int(size)
|
self._size = int(size)
|
||||||
self.flags = flags
|
self.flags = flags
|
||||||
self._action_id = "{}{}_part".format(self.parent.action_id,
|
self._action_id = "{}{}_part".format(self.parent.action_id,
|
||||||
self.partnumber)
|
self.partnum)
|
||||||
|
|
||||||
''' rename action_id for readability '''
|
''' rename action_id for readability '''
|
||||||
if self.flags in ['bios_grub']:
|
if self.flags in ['bios_grub']:
|
||||||
self._action_id = 'bios_boot_partition'
|
self._action_id = 'bios_boot_partition'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def path(self):
|
||||||
|
return "{}{}".format(self.parent.action_id, self.partnum)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def size(self):
|
def size(self):
|
||||||
return self._size
|
return self._size
|
||||||
|
|
||||||
|
@property
|
||||||
|
def offset(self):
|
||||||
|
return self._offset
|
||||||
|
|
||||||
def get(self):
|
def get(self):
|
||||||
return {
|
return {
|
||||||
'device': self.parent.action_id,
|
'device': self.parent.action_id,
|
||||||
'flag': self.flags,
|
'flag': self.flags,
|
||||||
'id': self.action_id,
|
'id': self.action_id,
|
||||||
'number': self.partnumber,
|
'number': self.partnum,
|
||||||
'size': '{}B'.format(self.size),
|
'size': '{}B'.format(self.size),
|
||||||
|
'offset': '{}B'.format(self.offset),
|
||||||
'type': 'partition',
|
'type': 'partition',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,10 +13,10 @@
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from collections import OrderedDict
|
||||||
from itertools import count
|
from itertools import count
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import parted
|
|
||||||
import re
|
import re
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
|
@ -57,45 +57,82 @@ class Bcachedev():
|
||||||
return self._path
|
return self._path
|
||||||
|
|
||||||
def getSize(self, unit='MB'):
|
def getSize(self, unit='MB'):
|
||||||
if type(self._backing) == parted.disk.Disk:
|
pass
|
||||||
return self._backing.device.getSize(unit=unit)
|
|
||||||
else:
|
|
||||||
return self._backing.getSize(unit=unit)
|
class Disk():
|
||||||
|
def __init__(self, devpath, serial, model, parttype, size=0):
|
||||||
|
self._devpath = devpath
|
||||||
|
self._serial = serial
|
||||||
|
self._parttype = parttype
|
||||||
|
self._model = model
|
||||||
|
self._size = self._get_size(devpath, size)
|
||||||
|
self._partitions = OrderedDict()
|
||||||
|
|
||||||
|
def _get_size(self, devpath, size):
|
||||||
|
if size:
|
||||||
|
return size
|
||||||
|
sysblock = os.path.join('/sys/block', os.path.basename(devpath))
|
||||||
|
nr_blocks_f = os.path.join(sysblock, 'size')
|
||||||
|
block_sz_f = os.path.join(sysblock, 'queue', 'logical_block_size')
|
||||||
|
with open(nr_blocks_f, 'r') as r:
|
||||||
|
nr_blocks = int(r.read())
|
||||||
|
with open(block_sz_f, 'r') as r:
|
||||||
|
block_sz = int(r.read())
|
||||||
|
|
||||||
|
return nr_blocks * block_sz
|
||||||
|
|
||||||
|
@property
|
||||||
|
def devpath(self):
|
||||||
|
return self._devpath
|
||||||
|
|
||||||
|
@property
|
||||||
|
def serial(self):
|
||||||
|
return self._serial
|
||||||
|
|
||||||
|
@property
|
||||||
|
def model(self):
|
||||||
|
return self._model
|
||||||
|
|
||||||
|
@property
|
||||||
|
def parttype(self):
|
||||||
|
return self._parttype
|
||||||
|
|
||||||
|
@property
|
||||||
|
def size(self):
|
||||||
|
return self._size
|
||||||
|
|
||||||
|
@property
|
||||||
|
def partitions(self):
|
||||||
|
return self._partitions
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
self._partitions = OrderedDict()
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class Blockdev():
|
class Blockdev():
|
||||||
def __init__(self, devpath, serial, parttype='gpt'):
|
def __init__(self, devpath, serial, model, parttype='gpt', size=0):
|
||||||
self.serial = serial
|
self.disk = Disk(devpath, serial, model, parttype, size)
|
||||||
self.devpath = devpath
|
self._filesystems = {}
|
||||||
self._parttype = parttype
|
|
||||||
self.device = parted.getDevice(self.devpath)
|
|
||||||
self.disk = parted.freshDisk(self.device, self.parttype)
|
|
||||||
self._mounts = {}
|
self._mounts = {}
|
||||||
self.bcache = []
|
self.bcache = []
|
||||||
self.lvm = []
|
self.lvm = []
|
||||||
|
self.baseaction = DiskAction(os.path.basename(self.disk.devpath),
|
||||||
|
self.disk.model, self.disk.serial,
|
||||||
|
self.disk.parttype)
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
''' Wipe out any actions queued for this disk '''
|
''' Wipe out any actions queued for this disk '''
|
||||||
self.disk = parted.freshDisk(self.device, self.parttype)
|
self.disk.reset()
|
||||||
|
self._filesystems = {}
|
||||||
self._mounts = {}
|
self._mounts = {}
|
||||||
self.bcache = []
|
self.bcache = []
|
||||||
self.lvm = []
|
self.lvm = []
|
||||||
|
|
||||||
def _get_largest_free_region(self):
|
@property
|
||||||
"""Finds largest free region on the disk"""
|
def devpath(self):
|
||||||
# There are better ways to do it, but let's be straightforward
|
return self.disk.devpath
|
||||||
max_size = -1
|
|
||||||
region = None
|
|
||||||
|
|
||||||
alignment = self.device.optimumAlignment
|
|
||||||
|
|
||||||
for r in self.disk.getFreeSpaceRegions():
|
|
||||||
# Heuristic: Ignore alignment gaps
|
|
||||||
if r.length > max_size and r.length > alignment.grainSize:
|
|
||||||
region = r
|
|
||||||
max_size = r.length
|
|
||||||
|
|
||||||
return region
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def mounts(self):
|
def mounts(self):
|
||||||
|
@ -103,7 +140,7 @@ class Blockdev():
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def parttype(self):
|
def parttype(self):
|
||||||
return self._parttype
|
return self.disk.parttype
|
||||||
|
|
||||||
@parttype.setter # NOQA
|
@parttype.setter # NOQA
|
||||||
def parttype(self, value):
|
def parttype(self, value):
|
||||||
|
@ -111,12 +148,16 @@ class Blockdev():
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def size(self):
|
def size(self):
|
||||||
return self.disk.device.getLength(unit='B')
|
return self.disk.size
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def partitions(self):
|
def partitions(self):
|
||||||
return self.disk.partitions
|
return self.disk.partitions
|
||||||
|
|
||||||
|
@property
|
||||||
|
def filesystems(self):
|
||||||
|
return self._filesystems
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def available(self):
|
def available(self):
|
||||||
''' return True if has free space or partitions not
|
''' return True if has free space or partitions not
|
||||||
|
@ -128,27 +169,27 @@ class Blockdev():
|
||||||
@property
|
@property
|
||||||
def usedspace(self, unit='b'):
|
def usedspace(self, unit='b'):
|
||||||
''' return amount of used space'''
|
''' return amount of used space'''
|
||||||
return sum([part.geometry.getSize(unit=unit) for part in
|
space = 0
|
||||||
self.disk.partitions])
|
for (num, action) in self.disk.partitions.items():
|
||||||
|
space += int(action.offset)
|
||||||
|
space += int(action.size)
|
||||||
|
|
||||||
|
log.debug('{} usedspace: {}'.format(self.disk.devpath, space))
|
||||||
|
return space
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def freespace(self, unit='B'):
|
def freespace(self, unit='B'):
|
||||||
''' return amount of free space '''
|
''' return amount of free space '''
|
||||||
geo = self._get_largest_free_region()
|
used = self.usedspace
|
||||||
if geo:
|
size = self.size
|
||||||
return geo.getLength(unit=unit)
|
log.debug('{} freespace: {} - {} = {}'.format(self.disk.devpath,
|
||||||
return 0
|
size, used,
|
||||||
|
size - used))
|
||||||
@property
|
return size - used
|
||||||
def freepartition(self, unit='b'):
|
|
||||||
''' return amount of partitionable space'''
|
|
||||||
return sum([part.geometry.getSize(unit=unit) for part in
|
|
||||||
self.disk.getFreeSpacePartitions()])
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def lastpartnumber(self):
|
def lastpartnumber(self):
|
||||||
return self.disk.lastPartitionNumber if \
|
return len(self.disk.partitions)
|
||||||
self.disk.lastPartitionNumber > 0 else 0
|
|
||||||
|
|
||||||
def delete_partition(self, partnum=None, sector=None, mountpoint=None):
|
def delete_partition(self, partnum=None, sector=None, mountpoint=None):
|
||||||
# find part and then call deletePartition()
|
# find part and then call deletePartition()
|
||||||
|
@ -161,77 +202,53 @@ class Blockdev():
|
||||||
' partnum:%s size:%s fstype:%s mountpoint:%s flag=%s' % (
|
' partnum:%s size:%s fstype:%s mountpoint:%s flag=%s' % (
|
||||||
partnum, size, fstype, mountpoint, flag))
|
partnum, size, fstype, mountpoint, flag))
|
||||||
|
|
||||||
if size > self.freepartition:
|
if size > self.freespace:
|
||||||
raise Exception('Not enough space')
|
raise Exception('Not enough space')
|
||||||
|
|
||||||
if fstype in ["swap"]:
|
if fstype in ["swap"]:
|
||||||
fstype = "linux-swap(v1)"
|
fstype = "linux-swap(v1)"
|
||||||
|
|
||||||
geometry = self._get_largest_free_region()
|
if len(self.disk.partitions) == 0:
|
||||||
if not geometry:
|
offset = 1 << 20 # 1K offset/aligned
|
||||||
raise Exception('No free sectors available')
|
size += offset
|
||||||
log.debug('largest free region:\n{}'.format(geometry))
|
|
||||||
|
|
||||||
# convert size into a geometry based on existing partitions
|
|
||||||
try:
|
|
||||||
start = self.disk.partitions[-1].geometry.end + 1
|
|
||||||
except IndexError:
|
|
||||||
start = 0
|
|
||||||
length = parted.sizeToSectors(size, 'B', self.device.sectorSize)
|
|
||||||
log.debug('requested start: {} length: {}'.format(start, length))
|
|
||||||
req_geo = parted.Geometry(self.device, start=start, length=length)
|
|
||||||
|
|
||||||
# find common area
|
|
||||||
parttype = parted.PARTITION_NORMAL
|
|
||||||
alignment = self.device.optimalAlignedConstraint
|
|
||||||
geometry = geometry.intersect(req_geo)
|
|
||||||
# update geometry with alignment
|
|
||||||
constraint = parted.Constraint(maxGeom=geometry).intersect(alignment)
|
|
||||||
data = {
|
|
||||||
'start': constraint.startAlign.alignUp(geometry, geometry.start),
|
|
||||||
'end': constraint.endAlign.alignDown(geometry, geometry.end),
|
|
||||||
}
|
|
||||||
geometry = parted.Geometry(device=self.device,
|
|
||||||
start=data['start'],
|
|
||||||
end=data['end'])
|
|
||||||
# create partition
|
|
||||||
if fstype not in [None, 'bcache cache', 'bcache store']:
|
|
||||||
fs = parted.FileSystem(type=fstype, geometry=geometry)
|
|
||||||
else:
|
else:
|
||||||
fs = None
|
offset = 0
|
||||||
partition = parted.Partition(disk=self.disk, type=parttype,
|
|
||||||
fs=fs, geometry=geometry)
|
|
||||||
|
|
||||||
# add flags
|
log.debug('requested start: {} length: {}'.format(offset, size))
|
||||||
flags = {
|
valid_flags = [
|
||||||
"boot": parted.PARTITION_BOOT,
|
"boot",
|
||||||
"lvm": parted.PARTITION_LVM,
|
"lvm",
|
||||||
"raid": parted.PARTITION_RAID,
|
"raid",
|
||||||
"bios_grub": parted.PARTITION_BIOS_GRUB
|
"bios_grub",
|
||||||
}
|
]
|
||||||
if flag in flags:
|
if flag and flag not in valid_flags:
|
||||||
partition.setFlag(flags[flag])
|
raise Exception('Flag: {} is not valid.'.format(flag))
|
||||||
|
|
||||||
self.disk.addPartition(partition=partition, constraint=constraint)
|
# create partition and add
|
||||||
|
part_action = PartitionAction(self.baseaction, partnum,
|
||||||
|
offset, size, flag)
|
||||||
|
log.debug('PartitionAction:\n{}'.format(part_action))
|
||||||
|
|
||||||
# fetch the newly created partition
|
self.disk.partitions.update({partnum: part_action})
|
||||||
partpath = "{}{}".format(self.disk.device.path, partition.number)
|
|
||||||
newpart = self.disk.getPartitionByPath(partpath)
|
|
||||||
|
|
||||||
# create bcachedev if neded
|
# record filesystem formating
|
||||||
if fstype and fstype.startswith('bcache'):
|
if fstype:
|
||||||
mode = fstype.split()[-1]
|
partpath = "{}{}".format(self.disk.devpath, partnum)
|
||||||
self.bcache.append(Bcachedev(backing=newpart, mode=mode))
|
fs_action = FormatAction(part_action, fstype)
|
||||||
|
log.debug('Adding filesystem: {}:{}'.format(partpath, fs_action))
|
||||||
|
self.filesystems.update({partpath: fs_action})
|
||||||
|
|
||||||
# associate partition devpath with mountpoint
|
# associate partition devpath with mountpoint
|
||||||
if mountpoint:
|
if mountpoint:
|
||||||
self._mounts[partpath] = mountpoint
|
self._mounts[partpath] = mountpoint
|
||||||
|
|
||||||
|
log.debug('Partition Added')
|
||||||
|
|
||||||
def is_mounted(self):
|
def is_mounted(self):
|
||||||
with open('/proc/mounts') as pm:
|
with open('/proc/mounts') as pm:
|
||||||
mounts = pm.read()
|
mounts = pm.read()
|
||||||
|
|
||||||
regexp = '{}.*'.format(self.disk.device.path)
|
regexp = '{}.*'.format(self.disk.devpath)
|
||||||
matches = re.findall(regexp, mounts)
|
matches = re.findall(regexp, mounts)
|
||||||
if len(matches) > 0:
|
if len(matches) > 0:
|
||||||
log.debug('Device is mounted: {}'.format(matches))
|
log.debug('Device is mounted: {}'.format(matches))
|
||||||
|
@ -245,28 +262,17 @@ class Blockdev():
|
||||||
return []
|
return []
|
||||||
|
|
||||||
actions = []
|
actions = []
|
||||||
baseaction = DiskAction(os.path.basename(self.disk.device.path),
|
action = self.baseaction.get()
|
||||||
self.device.model, self.serial, self.parttype)
|
for (num, part) in self.disk.partitions.items():
|
||||||
action = baseaction.get()
|
partpath = "{}{}".format(self.disk.devpath, part.partnum)
|
||||||
for part in self.disk.partitions:
|
actions.append(part)
|
||||||
fs_size = int(part.getSize(unit='B'))
|
if partpath in self.filesystems:
|
||||||
if part.fileSystem:
|
format_action = self.filesystems[partpath]
|
||||||
fs_type = part.fileSystem.type
|
|
||||||
else:
|
|
||||||
fs_type = None
|
|
||||||
flags = part.getFlagsAsString()
|
|
||||||
|
|
||||||
partition_action = PartitionAction(baseaction,
|
|
||||||
part.number,
|
|
||||||
fs_size, flags)
|
|
||||||
actions.append(partition_action)
|
|
||||||
if fs_type:
|
|
||||||
format_action = FormatAction(partition_action,
|
|
||||||
fs_type)
|
|
||||||
actions.append(format_action)
|
actions.append(format_action)
|
||||||
mountpoint = self._mounts.get(part.path)
|
|
||||||
if mountpoint:
|
if partpath in self._mounts:
|
||||||
mount_action = MountAction(format_action, mountpoint)
|
mount_action = MountAction(format_action,
|
||||||
|
self._mounts[partpath])
|
||||||
actions.append(mount_action)
|
actions.append(mount_action)
|
||||||
|
|
||||||
return [action] + [a.get() for a in actions]
|
return [action] + [a.get() for a in actions]
|
||||||
|
@ -274,14 +280,13 @@ class Blockdev():
|
||||||
def get_fs_table(self):
|
def get_fs_table(self):
|
||||||
''' list(mountpoint, humansize, fstype, partition_path) '''
|
''' list(mountpoint, humansize, fstype, partition_path) '''
|
||||||
fs_table = []
|
fs_table = []
|
||||||
for part in self.disk.partitions:
|
for (num, part) in self.disk.partitions.items():
|
||||||
if part.fileSystem:
|
partpath = "{}{}".format(self.disk.devpath, part.partnum)
|
||||||
mntpoint = self._mounts.get(part.path, part.fileSystem.type)
|
if partpath in self.filesystems:
|
||||||
fs_size = part.getSize(unit='B')
|
fs = self.filesystems[partpath]
|
||||||
fs_type = part.fileSystem.type
|
mntpoint = self._mounts.get(partpath, fs.fstype)
|
||||||
devpath = part.path
|
|
||||||
fs_table.append(
|
fs_table.append(
|
||||||
(mntpoint, fs_size, fs_type, devpath))
|
(mntpoint, part.size, fs.fstype, partpath))
|
||||||
|
|
||||||
return fs_table
|
return fs_table
|
||||||
|
|
||||||
|
@ -297,11 +302,17 @@ if __name__ == '__main__':
|
||||||
print("USED DISKS")
|
print("USED DISKS")
|
||||||
|
|
||||||
devices = []
|
devices = []
|
||||||
sda = Blockdev('/dev/sda', 'QM_TARGET_01', parttype='gpt')
|
#Blockdev(devpath, serial, model, parttype='gpt'):
|
||||||
sdb = Blockdev('/dev/sdb', 'dafunk')
|
GB = 1 << 30
|
||||||
|
sda = Blockdev('/dev/sda', 'QM_TARGET_01', 'QEMU SSD DISK',
|
||||||
|
parttype='gpt', size=128 * GB)
|
||||||
|
sdb = Blockdev('/dev/sdb', 'dafunk', 'QEMU SPINNER', size=500 * GB)
|
||||||
|
|
||||||
|
print(sda.freespace)
|
||||||
sda.add_partition(1, 8 * 1024 * 1024 * 1024, 'ext4', '/', 'bios_grub')
|
sda.add_partition(1, 8 * 1024 * 1024 * 1024, 'ext4', '/', 'bios_grub')
|
||||||
|
print(sda.freespace)
|
||||||
sda.add_partition(2, 2 * 1024 * 1024 * 1024, 'ext4', '/home')
|
sda.add_partition(2, 2 * 1024 * 1024 * 1024, 'ext4', '/home')
|
||||||
|
print(sda.freespace)
|
||||||
sdb.add_partition(1, 50 * 1024 * 1024 * 1024, 'btrfs', '/opt')
|
sdb.add_partition(1, 50 * 1024 * 1024 * 1024, 'btrfs', '/opt')
|
||||||
|
|
||||||
get_filesystems([sda, sdb])
|
get_filesystems([sda, sdb])
|
||||||
|
|
|
@ -134,13 +134,15 @@ class FilesystemModel(ModelPolicy):
|
||||||
|
|
||||||
def get_disk(self, disk):
|
def get_disk(self, disk):
|
||||||
if disk not in self.devices:
|
if disk not in self.devices:
|
||||||
self.devices[disk] = Blockdev(disk, self.info[disk].serial)
|
self.devices[disk] = Blockdev(disk, self.info[disk].serial,
|
||||||
|
self.info[disk].model)
|
||||||
return self.devices[disk]
|
return self.devices[disk]
|
||||||
|
|
||||||
def get_partitions(self):
|
def get_partitions(self):
|
||||||
partitions = []
|
partitions = []
|
||||||
for dev in self.devices.values():
|
for dev in self.devices.values():
|
||||||
partnames = [part.path for part in dev.disk.partitions]
|
partnames = [part.path for (num, part) in
|
||||||
|
dev.disk.partitions.items()]
|
||||||
partitions += partnames
|
partitions += partnames
|
||||||
|
|
||||||
sorted(partitions)
|
sorted(partitions)
|
||||||
|
|
Loading…
Reference in New Issue